evolution r37465 - in branches/kill-bonobo: a11y/e-table calendar/gui calendar/gui/dialogs composer e-util mail plugins/attachment-reminder plugins/import-ics-attachments shell widgets/misc widgets/table widgets/text



Author: mbarnes
Date: Fri Mar 20 19:06:59 2009
New Revision: 37465
URL: http://svn.gnome.org/viewvc/evolution?rev=37465&view=rev

Log:
Saving progress on a massive attachment handling rewrite.


Added:
   branches/kill-bonobo/widgets/misc/e-attachment-icon-view.c
   branches/kill-bonobo/widgets/misc/e-attachment-icon-view.h
   branches/kill-bonobo/widgets/misc/e-attachment-paned.c
   branches/kill-bonobo/widgets/misc/e-attachment-paned.h
   branches/kill-bonobo/widgets/misc/e-attachment-store.c
   branches/kill-bonobo/widgets/misc/e-attachment-store.h
   branches/kill-bonobo/widgets/misc/e-attachment-tree-view.c
   branches/kill-bonobo/widgets/misc/e-attachment-tree-view.h
   branches/kill-bonobo/widgets/misc/e-attachment-view.c
   branches/kill-bonobo/widgets/misc/e-attachment-view.h
Modified:
   branches/kill-bonobo/a11y/e-table/Makefile.am
   branches/kill-bonobo/calendar/gui/dialogs/comp-editor.c
   branches/kill-bonobo/calendar/gui/e-cal-popup.c
   branches/kill-bonobo/composer/e-composer-actions.c
   branches/kill-bonobo/composer/e-composer-private.c
   branches/kill-bonobo/composer/e-composer-private.h
   branches/kill-bonobo/composer/e-msg-composer.c
   branches/kill-bonobo/composer/e-msg-composer.h
   branches/kill-bonobo/e-util/Makefile.am
   branches/kill-bonobo/e-util/e-util.c
   branches/kill-bonobo/e-util/e-util.h
   branches/kill-bonobo/mail/e-mail-browser.c
   branches/kill-bonobo/mail/e-mail-reader.c
   branches/kill-bonobo/mail/em-format-html-display.c
   branches/kill-bonobo/mail/em-format-html-display.h
   branches/kill-bonobo/mail/em-popup.c
   branches/kill-bonobo/plugins/attachment-reminder/attachment-reminder.c
   branches/kill-bonobo/plugins/import-ics-attachments/icsimporter.c
   branches/kill-bonobo/shell/e-shell.c
   branches/kill-bonobo/shell/main.c
   branches/kill-bonobo/widgets/misc/Makefile.am
   branches/kill-bonobo/widgets/misc/e-activity.c
   branches/kill-bonobo/widgets/misc/e-activity.h
   branches/kill-bonobo/widgets/misc/e-attachment-bar.c
   branches/kill-bonobo/widgets/misc/e-attachment-dialog.c
   branches/kill-bonobo/widgets/misc/e-attachment.c
   branches/kill-bonobo/widgets/misc/e-attachment.h
   branches/kill-bonobo/widgets/misc/e-file-activity.c
   branches/kill-bonobo/widgets/misc/e-file-activity.h
   branches/kill-bonobo/widgets/misc/e-timeout-activity.c
   branches/kill-bonobo/widgets/misc/e-timeout-activity.h
   branches/kill-bonobo/widgets/table/Makefile.am
   branches/kill-bonobo/widgets/text/Makefile.am

Modified: branches/kill-bonobo/a11y/e-table/Makefile.am
==============================================================================
--- branches/kill-bonobo/a11y/e-table/Makefile.am	(original)
+++ branches/kill-bonobo/a11y/e-table/Makefile.am	Fri Mar 20 19:06:59 2009
@@ -1,6 +1,7 @@
 INCLUDES =					\
-	-I$(top_srcdir)                         \
-	-I$(top_srcdir)/widgets                 \
+	-I$(top_srcdir)				\
+	-I$(top_srcdir)/widgets			\
+	$(E_UTIL_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)		\
         -DG_LOG_DOMAIN=\"e-table\"
 

Modified: branches/kill-bonobo/calendar/gui/dialogs/comp-editor.c
==============================================================================
--- branches/kill-bonobo/calendar/gui/dialogs/comp-editor.c	(original)
+++ branches/kill-bonobo/calendar/gui/dialogs/comp-editor.c	Fri Mar 20 19:06:59 2009
@@ -63,9 +63,8 @@
 #include "../e-cal-popup.h"
 #include "../calendar-config-keys.h"
 #include "cal-attachment-select-file.h"
+#include "widgets/misc/e-attachment-paned.h"
 
-#include "e-attachment-bar.h"
-#include "misc/e-expander.h"
 #include "e-util/e-error.h"
 
 #define COMP_EDITOR_GET_PRIVATE(obj) \
@@ -95,12 +94,7 @@
 	GtkNotebook *notebook;
 
 	/* Attachment handling */
-	GtkWidget *attachment_bar;
-	GtkWidget *attachment_scrolled_window;
-	GtkWidget *attachment_expander;
-	GtkWidget *attachment_expander_label;
-	GtkWidget *attachment_expander_icon;
-	GtkWidget *attachment_expander_num;
+	GtkWidget *attachment_paned;
 
 	/* Manages menus and toolbars */
 	GtkUIManager *manager;
@@ -169,7 +163,6 @@
 "</ui>";
 
 static void comp_editor_show_help (CompEditor *editor);
-static void setup_widgets (CompEditor *editor);
 
 static void real_edit_comp (CompEditor *editor, ECalComponent *comp);
 static gboolean real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean strip_alarms);
@@ -232,391 +225,82 @@
 }
 
 static void
-attach_message(CompEditor *editor, CamelMimeMessage *msg)
+drag_data_received (CompEditor *editor,
+                    GdkDragContext *context,
+                    gint x,
+                    gint y,
+                    GtkSelectionData *selection,
+                    guint info,
+                    guint time)
 {
-	CamelMimePart *mime_part;
-	const char *subject;
-	guint i;
-	char *filename = NULL;
-
-	mime_part = camel_mime_part_new();
-	camel_mime_part_set_disposition(mime_part, "inline");
-	subject = camel_mime_message_get_subject(msg);
-	if (subject) {
-		char *desc = g_strdup_printf(_("Attached message - %s"), subject);
-
-		camel_mime_part_set_description(mime_part, desc);
-		g_free(desc);
-	} else
-		camel_mime_part_set_description(mime_part, _("Attached message"));
-
-	i = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	i++;
-	filename = g_strdup_printf ("email%d",i);
-	camel_mime_part_set_filename (mime_part, filename);
-
-	camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
-	camel_mime_part_set_content_type(mime_part, "message/rfc822");
-	e_attachment_bar_attach_mime_part(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
-	camel_object_unref(mime_part);
-	g_free (filename);
-}
-
-struct _drop_data {
-	CompEditor *editor;
-
-	GdkDragContext *context;
-	/* Only selection->data and selection->length are valid */
-	GtkSelectionData *selection;
-
-	guint32 action;
-	guint info;
-	guint time;
-
-	unsigned int move:1;
-	unsigned int moved:1;
-	unsigned int aborted:1;
-};
-
-static void
-drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
-{
-#if 0  /* KILL-BONOBO */
-	char *tmp, *str, **urls;
-	CamelMimePart *mime_part;
-	CamelStream *stream;
-	CamelURL *url;
-	CamelMimeMessage *msg;
-	char *content_type;
-	int i, success=FALSE, delete=FALSE;
-
-	switch (info) {
-	case DND_TYPE_MESSAGE_RFC822:
-		d(printf ("dropping a message/rfc822\n"));
-		/* write the message(s) out to a CamelStream so we can use it */
-		stream = camel_stream_mem_new ();
-		camel_stream_write (stream, (char *)selection->data, selection->length);
-		camel_stream_reset (stream);
-
-		msg = camel_mime_message_new ();
-		if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
-			attach_message(editor, msg);
-			success = TRUE;
-			delete = action == GDK_ACTION_MOVE;
-		}
-
-		camel_object_unref(msg);
-		camel_object_unref(stream);
-		break;
-	case DND_TYPE_TEXT_URI_LIST:
-	case DND_TYPE_NETSCAPE_URL:
-		d(printf ("dropping a text/uri-list\n"));
-		tmp = g_strndup ((char *)selection->data, selection->length);
-		urls = g_strsplit (tmp, "\n", 0);
-		g_free (tmp);
-
-		for (i = 0; urls[i] != NULL; i++) {
-			str = g_strstrip (urls[i]);
-			if (urls[i][0] == '#')
-				continue;
-
-			if (!g_ascii_strncasecmp (str, "mailto:";, 7)) {
-				/* TODO does not handle mailto now */
-			} else {
-				url = camel_url_new (str, NULL);
-
-				if (url == NULL)
-					continue;
-
-				if (!g_ascii_strcasecmp (url->protocol, "file"))
-					e_attachment_bar_attach
-						(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-					 	url->path,
-						"attachment");
-				else
-					e_attachment_bar_attach_remote_file
-						(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-						 str, "attachment");
-
-				camel_url_free (url);
-			}
-		}
+	EAttachmentPaned *paned;
+	EAttachmentView *view;
 
-		g_strfreev (urls);
-		success = TRUE;
-		break;
-	case DND_TYPE_TEXT_VCARD:
-	case DND_TYPE_TEXT_CALENDAR:
-		content_type = gdk_atom_name (selection->type);
-		d(printf ("dropping a %s\n", content_type));
-
-		mime_part = camel_mime_part_new ();
-		camel_mime_part_set_content (mime_part, (char *)selection->data, selection->length, content_type);
-		camel_mime_part_set_disposition (mime_part, "inline");
-
-		e_attachment_bar_attach_mime_part
-			(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-			 mime_part);
-
-		camel_object_unref (mime_part);
-		g_free (content_type);
-
-		success = TRUE;
-		break;
-	case DND_TYPE_X_UID_LIST: {
-		GPtrArray *uids;
-		char *inptr, *inend;
-		CamelFolder *folder;
-		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
-		/* NB: This all runs synchronously, could be very slow/hang/block the ui */
-
-		uids = g_ptr_array_new();
-
-		inptr = (char *)selection->data;
-		inend = (char *)(selection->data + selection->length);
-		while (inptr < inend) {
-			char *start = inptr;
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
 
-			while (inptr < inend && *inptr)
-				inptr++;
-
-			if (start > (char *)selection->data)
-				g_ptr_array_add(uids, g_strndup(start, inptr-start));
-
-			inptr++;
-		}
-
-		if (uids->len > 0) {
-			folder = mail_tool_uri_to_folder((char *)selection->data, 0, &ex);
-			if (folder) {
-				if (uids->len == 1) {
-					msg = camel_folder_get_message(folder, uids->pdata[0], &ex);
-					if (msg == NULL)
-						goto fail;
-					attach_message(editor, msg);
-				} else {
-					CamelMultipart *mp = camel_multipart_new();
-					char *desc;
-					char *filename = NULL;
-					guint num;
-
-					camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/digest");
-					camel_multipart_set_boundary(mp, NULL);
-					for (i=0;i<uids->len;i++) {
-
-						msg = camel_folder_get_message(folder, uids->pdata[i], &ex);
-						if (msg) {
-							mime_part = camel_mime_part_new();
-							camel_mime_part_set_disposition(mime_part, "inline");
-							camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
-							camel_mime_part_set_content_type(mime_part, "message/rfc822");
-							camel_multipart_add_part(mp, mime_part);
-							camel_object_unref(mime_part);
-							camel_object_unref(msg);
-						} else {
-							camel_object_unref(mp);
-							goto fail;
-						}
-					}
-					mime_part = camel_mime_part_new();
-					camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)mp);
-					/* translators, this count will always be >1 */
-					desc = g_strdup_printf(ngettext("Attached message", "%d attached messages", uids->len), uids->len);
-					camel_mime_part_set_description(mime_part, desc);
-					g_free(desc);
-
-					num = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-					num++;
-					filename = g_strdup_printf ("email%d", num);
-					camel_mime_part_set_filename (mime_part, filename);
-
-					e_attachment_bar_attach_mime_part
-						(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
-					camel_object_unref(mime_part);
-					camel_object_unref(mp);
-					g_free (filename);
-				}
-				success = TRUE;
-				delete = action == GDK_ACTION_MOVE;
-			fail:
-				if (camel_exception_is_set(&ex)) {
-					char *name;
-
-					camel_object_get(folder, NULL, CAMEL_FOLDER_NAME, &name, NULL);
-					e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
-						    name?name:(char *)selection->data, camel_exception_get_description(&ex), NULL);
-					camel_object_free(folder, CAMEL_FOLDER_NAME, name);
-				}
-				camel_object_unref(folder);
-			} else {
-				e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
-					    (char *)selection->data, camel_exception_get_description(&ex), NULL);
-			}
-
-			camel_exception_clear(&ex);
-		}
-
-		g_ptr_array_free(uids, TRUE);
-
-		break; }
-	default:
-		d(printf ("dropping an unknown\n"));
-		break;
-	}
-
-	printf("Drag finished, success %d delete %d\n", success, delete);
-
-	gtk_drag_finish(context, success, delete, time);
-#endif
-}
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	drop_action(m->editor, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	drop_action(m->editor, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	gtk_drag_finish(m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
-	{ E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
-	{ E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
-	{ E_POPUP_BAR, "10.emc" },
-	{ E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
-	struct _drop_data *m = data;
-
-	g_slist_free(items);
-
-	g_object_unref(m->context);
-	g_object_unref(m->editor);
-	g_free(m->selection->data);
-	g_free(m->selection);
-	g_free(m);
-}
-
-static void
-drag_data_received (CompEditor *editor, GdkDragContext *context,
-		    int x, int y, GtkSelectionData *selection,
-		    guint info, guint time)
-{
-	if (selection->data == NULL || selection->length == -1)
-		return;
-
-	if (context->action == GDK_ACTION_ASK) {
-		ECalPopup *ecp;
-		GSList *menus = NULL;
-		GtkMenu *menu;
-		int i;
-		struct _drop_data *m;
-
-		m = g_malloc0(sizeof(*m));
-		m->context = context;
-		g_object_ref(context);
-		m->editor = editor;
-		g_object_ref(editor);
-		m->action = context->action;
-		m->info = info;
-		m->time = time;
-		m->selection = g_malloc0(sizeof(*m->selection));
-		m->selection->data = g_malloc(selection->length);
-		memcpy(m->selection->data, selection->data, selection->length);
-		m->selection->length = selection->length;
-
-		ecp = e_cal_popup_new("org.gnome.evolution.calendar.editor.popup.drop");
-		for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
-			menus = g_slist_append(menus, &drop_popup_menu[i]);
-
-		e_popup_add_items((EPopup *)ecp, menus, NULL, drop_popup_free, m);
-		menu = e_popup_create_menu_once((EPopup *)ecp, NULL, 0);
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
-	} else {
-		drop_action(editor, context, context->action, selection, info, time);
-	}
+	e_attachment_view_drag_data_received (
+		view, context, x, y, selection, info, time);
 }
 
 static gboolean
-drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, CompEditor *editor)
+drag_motion (CompEditor *editor,
+             GdkDragContext *context,
+             gint x,
+             gint y,
+             guint time)
 {
-	GList *targets;
-	GdkDragAction action, actions = 0;
+	EAttachmentPaned *paned;
+	EAttachmentView *view;
 
-	for (targets = context->targets; targets; targets = targets->next) {
-		int i;
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
 
-		for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
-			if (targets->data == (void *)drag_info[i].atom)
-				actions |= drag_info[i].actions;
-	}
-
-	actions &= context->actions;
-	action = context->suggested_action;
-	/* we default to copy */
-	if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
-		action = GDK_ACTION_COPY;
-
-	gdk_drag_status(context, action, time);
-
-	return action != 0;
-}
-
-static void
-add_to_bar (CompEditor *editor, GPtrArray *file_list, int is_inline)
-{
-	CompEditorPrivate *priv = editor->priv;
-	int i;
-
-	for (i = 0; i < file_list->len; i++) {
-		CamelURL *url;
-
-		if (!(url = camel_url_new (file_list->pdata[i], NULL)))
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file")) {
-			e_attachment_bar_attach((EAttachmentBar *)priv->attachment_bar, url->path, is_inline ? "inline" : "attachment");
-		} else {
-			e_attachment_bar_attach_remote_file ((EAttachmentBar *)priv->attachment_bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
-		}
-
-		camel_url_free (url);
-	}
+	return e_attachment_view_drag_motion (view, context, x, y, time);
 }
 
 static GSList *
 get_attachment_list (CompEditor *editor)
 {
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
 	GSList *parts = NULL, *list = NULL, *p = NULL;
 	const char *comp_uid = NULL;
 	const char *local_store = e_cal_get_local_attachment_store (editor->priv->client);
+	gboolean valid;
 	int ticker=0;
+
 	e_cal_component_get_uid (editor->priv->comp, &comp_uid);
 
-	parts = e_attachment_bar_get_parts((EAttachmentBar *)editor->priv->attachment_bar);
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
 
-	for (p = parts; p!=NULL ; p = p->next) {
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	while (valid) {
+		EAttachment *attachment;
 		CamelDataWrapper *wrapper;
+		CamelMimePart *mime_part;
 		CamelStream *stream;
 		char *attach_file_url;
 		char *safe_fname, *utf8_safe_fname;
 		char *filename;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		mime_part = e_attachment_get_mime_part (attachment);
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+
+		if (mime_part == NULL)
+			continue;
 
 		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (p->data));
 
@@ -997,20 +681,15 @@
 action_attach_cb (GtkAction *action,
                   CompEditor *editor)
 {
-	GPtrArray *file_list;
-	gboolean is_inline = FALSE;
-	int i;
-
-	file_list = comp_editor_select_file_attachments (editor, &is_inline);
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
 
-	if (file_list) {
-		add_to_bar (editor, file_list, is_inline);
-
-		for (i = 0; i < file_list->len; i++)
-			g_free (file_list->pdata[i]);
-
-		g_ptr_array_free (file_list, TRUE);
-	}
+	e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor));
 }
 
 static void
@@ -1136,12 +815,19 @@
                 CompEditor *editor)
 {
 	CompEditorPrivate *priv = editor->priv;
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
 	ECalComponentText text;
 	gboolean delegated = FALSE;
 	gboolean read_only, correct = FALSE;
 	ECalComponent *comp;
 
-	if (e_attachment_bar_get_download_count (E_ATTACHMENT_BAR (editor->priv->attachment_bar)) ){
+	paned = E_ATTACHMENT_PANED (priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
+
+	if (e_attachment_store_get_num_downloading (store) > 0) {
 		gboolean response = 1;
 	/*FIXME: Cannot use mail functions from calendar!!!! */
 #if 0
@@ -1693,6 +1379,44 @@
 	GTK_WIDGET_CLASS (comp_editor_parent_class)->map (widget);
 }
 
+static gboolean
+comp_editor_delete_event (GtkWidget *widget,
+                          GdkEventAny *event)
+{
+	CompEditor *editor;
+
+	editor = COMP_EDITOR (widget);
+
+	commit_all_fields (editor);
+
+	if (prompt_and_save_changes (editor, TRUE))
+		close_dialog (editor);
+
+	return TRUE;
+}
+
+static gboolean
+comp_editor_key_press_event (GtkWidget *widget,
+                             GdkEventKey *event)
+{
+	CompEditor *editor;
+
+	editor = COMP_EDITOR (editor);
+
+	if (event->keyval == GDK_Escape) {
+		commit_all_fields (editor);
+
+		if (prompt_and_save_changes (editor, TRUE))
+			close_dialog (editor);
+
+		return TRUE;
+	}
+
+	/* Chain up to parent's key_press_event() method. */
+	return GTK_WIDGET_CLASS (comp_editor_parent_class)->
+		key_press_event (widget, event);
+}
+
 static void
 comp_editor_class_init (CompEditorClass *class)
 {
@@ -1713,6 +1437,8 @@
 
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->map = comp_editor_map;
+	widget_class->delete_event = comp_editor_delete_event;
+	widget_class->key_press_event = comp_editor_key_press_event;
 
 	class->help_section = "usage-calendar";
 	class->edit_comp = real_edit_comp;
@@ -1778,8 +1504,12 @@
 comp_editor_init (CompEditor *editor)
 {
 	CompEditorPrivate *priv;
+	EAttachmentPaned *paned;
+	EAttachmentView *view;
 	GtkActionGroup *action_group;
 	GtkAction *action;
+	GtkWidget *container;
+	GtkWidget *widget;
 	EShell *shell;
 	GError *error = NULL;
 
@@ -1795,17 +1525,18 @@
 	priv->changed = FALSE;
 	priv->needs_send = FALSE;
 	priv->mod = CALOBJ_MOD_ALL;
- 	priv->existing_org = FALSE;
- 	priv->user_org = FALSE;
- 	priv->warned = FALSE;
+	priv->existing_org = FALSE;
+	priv->user_org = FALSE;
+	priv->warned = FALSE;
 	priv->is_group_item = FALSE;
 
-	priv->attachment_bar = e_attachment_bar_new ();
 	priv->manager = gtk_ui_manager_new ();
 
-        gtk_window_add_accel_group (
-                GTK_WINDOW (editor),
-                gtk_ui_manager_get_accel_group (priv->manager));
+	gtk_window_add_accel_group (
+		GTK_WINDOW (editor),
+		gtk_ui_manager_get_accel_group (priv->manager));
+
+	/* Setup Action Groups */
 
 	action_group = gtk_action_group_new ("core");
 	gtk_action_group_set_translation_domain (
@@ -1831,10 +1562,6 @@
 		G_N_ELEMENTS (classification_radio_entries),
 		E_CAL_COMPONENT_CLASS_PUBLIC,
 		NULL, NULL);  /* no callback */
-	action = e_attachment_bar_recent_action_new (
-		E_ATTACHMENT_BAR (priv->attachment_bar),
-		"attach-recent", _("Recent _Documents"));
-	gtk_action_group_add_action (action_group, action);
 	gtk_ui_manager_insert_action_group (
 		priv->manager, action_group, 0);
 	g_object_unref (action_group);
@@ -1864,12 +1591,52 @@
 		g_error_free (error);
 	}
 
-	setup_widgets (editor);
+	/* Setup Widgets */
+
+	container = GTK_WIDGET (editor);
+
+	widget = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = comp_editor_get_managed_widget (editor, "/main-menu");
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	widget = e_attachment_paned_new ();
+	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->attachment_paned = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = e_attachment_paned_get_content_area (
+		E_ATTACHMENT_PANED (priv->attachment_paned));
+
+	widget = gtk_notebook_new ();
+	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->notebook = GTK_NOTEBOOK (widget);
+	gtk_widget_show (widget);
+
+	/* Add a GtkRecentAction to the "individual" action group. */
+	action_group = comp_editor_get_action_group (editor, "individual");
+	paned = E_ATTACHMENT_PANED (priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	action = e_attachment_view_recent_action_new (
+		view, "attach-recent", _("Recent _Documents"));
+	gtk_action_group_add_action (action_group, action);
+	g_object_unref (action);
 
 	/* DND support */
 	gtk_drag_dest_set (GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL,  drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
 	g_signal_connect(editor, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
-	g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), editor);
+	g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), NULL);
 
 	gtk_window_set_type_hint (GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
 
@@ -1928,170 +1695,17 @@
 	}
 }
 
-static int
-delete_event_cb (GtkWidget *widget,
-                 GdkEvent *event,
-                 CompEditor *editor)
-{
-	commit_all_fields (editor);
-
-	if (prompt_and_save_changes (editor, TRUE))
-		close_dialog (editor);
-
-	return TRUE;
-}
-
 static void
-attachment_bar_changed_cb (EAttachmentBar *bar,
-                           CompEditor *editor)
+attachment_store_changed_cb (CompEditor *editor)
 {
-	guint attachment_num = e_attachment_bar_get_num_attachments (
-		E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	if (attachment_num) {
-		gchar *num_text = g_strdup_printf (
-			ngettext ("<b>%d</b> Attachment", "<b>%d</b> Attachments", attachment_num),
-			attachment_num);
-		gtk_label_set_markup (GTK_LABEL (editor->priv->attachment_expander_num),
-				      num_text);
-		g_free (num_text);
-
-		gtk_widget_show (editor->priv->attachment_expander_icon);
-		e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),TRUE);
-
-	} else {
-		gtk_label_set_text (GTK_LABEL (editor->priv->attachment_expander_num), "");
-		gtk_widget_hide (editor->priv->attachment_expander_icon);
-		e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),FALSE);
-	}
-
-
 	/* Mark the editor as changed so it prompts about unsaved
            changes on close */
 	comp_editor_set_changed (editor, TRUE);
-
-}
-
-static void
-attachment_expander_activate_cb (EExpander *expander,
-				 void *data)
-{
-	CompEditor *editor = COMP_EDITOR (data);
-	gboolean show = e_expander_get_expanded (expander);
-
-	/* Update the expander label */
-	if (show)
-		gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
-					          _("Hide Attachment _Bar"));
-	else
-		gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
-						  _("Show Attachment _Bar"));
-}
-
-
-/* GtkWidget methods.  */
-
-static gint
-editor_key_press_event (CompEditor *editor,
-                        GdkEventKey *event)
-{
-        if (event->keyval == GDK_Escape) {
-		commit_all_fields (editor);
-
-		if (prompt_and_save_changes (editor, TRUE))
-			close_dialog (editor);
-
-                return TRUE;
-        }
-
-        return FALSE;
 }
 
 /* Menu callbacks */
 
 static void
-setup_widgets (CompEditor *editor)
-{
-	CompEditorPrivate *priv;
-	GtkWidget *expander_hbox;
-	GtkWidget *widget;
-	GtkWidget *vbox;
-
-	priv = editor->priv;
-
-	/* Useful vbox */
-	vbox = gtk_vbox_new (FALSE, 0);
-	gtk_container_add (GTK_CONTAINER (editor), vbox);
-	gtk_widget_show (vbox);
-
-	/* Main Menu */
-	widget = comp_editor_get_managed_widget (editor, "/main-menu");
-	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	/* Main Toolbar */
-	widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
-	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	/* Notebook */
-	widget = gtk_notebook_new ();
-	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
-	gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
-	gtk_widget_show (widget);
-	priv->notebook = GTK_NOTEBOOK (widget);
-
-	g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), editor);
-	g_signal_connect (editor, "key_press_event", G_CALLBACK (editor_key_press_event), editor);
-
-	/*Attachments */
-	priv->attachment_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
-					     GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
-					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
-	GTK_WIDGET_SET_FLAGS (priv->attachment_bar, GTK_CAN_FOCUS);
-	gtk_container_add (GTK_CONTAINER (priv->attachment_scrolled_window),
-			   priv->attachment_bar);
-	gtk_widget_show (priv->attachment_bar);
-	g_signal_connect (priv->attachment_bar, "changed",
-			  G_CALLBACK (attachment_bar_changed_cb), editor);
-	priv->attachment_expander_label =
-		gtk_label_new_with_mnemonic (_("Show Attachment _Bar"));
-	priv->attachment_expander_num = gtk_label_new ("");
-	gtk_label_set_use_markup (GTK_LABEL (priv->attachment_expander_num), TRUE);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_label), 0.0, 0.5);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_num), 1.0, 0.5);
-	expander_hbox = gtk_hbox_new (FALSE, 0);
-
-	priv->attachment_expander_icon = gtk_image_new_from_icon_name ("mail-attachment", GTK_ICON_SIZE_MENU);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_icon), 1, 0.5);
-	gtk_widget_set_size_request (priv->attachment_expander_icon, 100, -1);
-
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_label,
-			    TRUE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_icon,
-			    TRUE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_num,
-			    TRUE, TRUE, 0);
-	gtk_widget_show_all (expander_hbox);
-	gtk_widget_hide (priv->attachment_expander_icon);
-
-	priv->attachment_expander = e_expander_new ("");
-	e_expander_set_label_widget (E_EXPANDER (priv->attachment_expander), expander_hbox);
-	atk_object_set_name (gtk_widget_get_accessible (priv->attachment_expander), _("Show Attachments"));
-	atk_object_set_description (gtk_widget_get_accessible (priv->attachment_expander), _("Press space key to toggle attachment bar"));
-	gtk_container_add (GTK_CONTAINER (priv->attachment_expander), priv->attachment_scrolled_window);
-
-	gtk_box_pack_start (GTK_BOX (vbox), priv->attachment_expander, FALSE, FALSE, 4);
-	gtk_widget_show (priv->attachment_expander);
-	e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), FALSE);
-	g_signal_connect_after (priv->attachment_expander, "activate",
-				G_CALLBACK (attachment_expander_activate_cb), editor);
-}
-
-
-static void
 comp_editor_show_help (CompEditor *editor)
 {
 	CompEditorClass *class;
@@ -2637,12 +2251,16 @@
 static void
 set_attachment_list (CompEditor *editor, GSList *attach_list)
 {
-	GSList *p = NULL;
-	const char *comp_uid= NULL;
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GSList *iter = NULL;
+
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
 
-	e_cal_component_get_uid (editor->priv->comp, &comp_uid);
-
-	if (e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar))) {
+	if (e_attachment_store_get_num_attachments (store) > 0) {
 		/* To prevent repopulating the
 		 * bar due to redraw functions in fill_widget.
 		 * Assumes it can be set only once.
@@ -2650,100 +2268,42 @@
 		return;
 	}
 
-	for (p = attach_list; p != NULL; p = p->next) {
-		char *attach_filename;
-		CamelMimePart *part;
-		CamelDataWrapper *wrapper;
-		CamelStream *stream;
-		struct stat statbuf;
-		char *mime_type, *file_name;
-		char *ptr;
-
-		attach_filename = (char *) p->data;
-		/* should we assert if g_str_has_prefix (attach_filename, "file://"))
-		 * here
-		*/
-		/* get url sans protocol and add it to the bar.
-		 * how to set the filename properly */
-		file_name = g_filename_from_uri (attach_filename, NULL, NULL);
-		if (!file_name)
-			continue;
-
-		if (g_stat (file_name, &statbuf) < 0) {
-			g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
-			g_free (file_name);
-			continue;
-		}
-
-		/* return if it's not a regular file */
-		if (!S_ISREG (statbuf.st_mode)) {
-			g_warning ("Cannot attach file %s: not a regular file", file_name);
-			g_free (file_name);
-			return;
-		}
-
-		stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0);
-		if (!stream) {
-			g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
-			g_free (file_name);
-			return;
-		}
-
-		mime_type = e_util_guess_mime_type (file_name, TRUE);
-		if (mime_type) {
-			if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-				wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-			} else {
-				wrapper = camel_data_wrapper_new ();
-			}
-
-			camel_data_wrapper_construct_from_stream (wrapper, stream);
-			camel_data_wrapper_set_mime_type (wrapper, mime_type);
-			g_free (mime_type);
-		} else {
-			wrapper = camel_data_wrapper_new ();
-			camel_data_wrapper_construct_from_stream (wrapper, stream);
-			camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-		}
-
-		camel_object_unref (stream);
-
-		part = camel_mime_part_new ();
-		camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
-		camel_object_unref (wrapper);
-
-		camel_mime_part_set_disposition (part, "attachment");
-
-		ptr = strstr (file_name, comp_uid);
-		if (ptr) {
-			ptr += strlen(comp_uid);
-			if (*ptr++ == '-')
-				camel_mime_part_set_filename (part, ptr);
-		}
-		g_free (file_name);
-
-		e_attachment_bar_attach_mime_part ((EAttachmentBar *) editor->priv->attachment_bar, part);
-		e_expander_set_expanded (E_EXPANDER (editor->priv->attachment_expander), TRUE);
-
-		camel_object_unref (part);
+	for (iter = attach_list; iter != NULL; iter = iter->next) {
+		EAttachment *attachment;
+		const gchar *uri = iter->data;
+
+		attachment = e_attachment_new_for_uri (uri);
+		e_attachment_store_add_attachment (store, attachment);
+		g_object_unref (attachment);
 	}
 }
 
 static void
 fill_widgets (CompEditor *editor)
 {
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
 	CompEditorPrivate *priv;
 	GList *l;
 
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
+
 	priv = editor->priv;
 
 	/*Check if attachments are available here and set them*/
 	if (e_cal_component_has_attachments (priv->comp)) {
 		GSList *attachment_list = NULL;
 		e_cal_component_get_attachment_list (priv->comp, &attachment_list);
-		g_signal_handlers_block_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+		g_signal_handlers_block_by_func (
+			store, G_CALLBACK (attachment_store_changed_cb),
+			editor);
 		set_attachment_list (editor, attachment_list);
-		g_signal_handlers_unblock_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+		g_signal_handlers_unblock_by_func(
+			store, G_CALLBACK (attachment_store_changed_cb),
+			editor);
 		g_slist_foreach (attachment_list, (GFunc)g_free, NULL);
 		g_slist_free (attachment_list);
 	}
@@ -3068,20 +2628,43 @@
 GSList *
 comp_editor_get_mime_attach_list (CompEditor *editor)
 {
+	EAttachmentPaned *paned;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
 	struct CalMimeAttach *cal_mime_attach;
-	GSList *attach_list = NULL, *l, *parts;
+	GSList *attach_list = NULL;
+	gboolean valid;
+
+	paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
 
-	/* TODO assert sanity of bar */
-	parts = e_attachment_bar_get_parts (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	for (l = parts; l ; l = l->next) {
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
 
+	while (valid) {
+		EAttachment *attachment;
 		CamelDataWrapper *wrapper;
+		CamelMimePart *mime_part;
 		CamelStreamMem *mstream;
 		unsigned char *buffer = NULL;
 		const char *desc, *disp;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		mime_part = e_attachment_get_mime_part (attachment);
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+
+		if (mime_part == NULL)
+			continue;
 
 		cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach));
-		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (l->data));
+		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 		mstream = (CamelStreamMem *) camel_stream_mem_new ();
 
 		camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
@@ -3089,15 +2672,14 @@
 
 		cal_mime_attach->encoded_data = (char *)buffer;
 		cal_mime_attach->length = mstream->buffer->len;
-		cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename
-			((CamelMimePart *) l->data));
-		desc = camel_mime_part_get_description ((CamelMimePart *) l->data);
+		cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename (mime_part));
+		desc = camel_mime_part_get_description (mime_part);
 		if (!desc || *desc == '\0')
 			desc = _("attachment");
 		cal_mime_attach->description = g_strdup (desc);
 		cal_mime_attach->content_type = g_strdup (camel_data_wrapper_get_mime_type (wrapper));
 
-		disp = camel_mime_part_get_disposition ((CamelMimePart *)l->data);
+		disp = camel_mime_part_get_disposition (mime_part);
 		if (disp && !g_ascii_strcasecmp(disp, "inline"))
 			cal_mime_attach->disposition = TRUE;
 
@@ -3107,8 +2689,6 @@
 
 	}
 
-	g_slist_free (parts);
-
 	return attach_list;
 }
 

Modified: branches/kill-bonobo/calendar/gui/e-cal-popup.c
==============================================================================
--- branches/kill-bonobo/calendar/gui/e-cal-popup.c	(original)
+++ branches/kill-bonobo/calendar/gui/e-cal-popup.c	Fri Mar 20 19:06:59 2009
@@ -86,395 +86,11 @@
 
 /* Standard menu code */
 
-static char *
-temp_save_part(CamelMimePart *part, char *path, gboolean file)
-{
-	const char *filename;
-	char *tmpdir, *utf8_mfilename = NULL, *mfilename = NULL, *usepath;
-	CamelStream *stream;
-	CamelDataWrapper *wrapper;
-
-	if (!path) {
-		tmpdir = e_mkdtemp("evolution-tmp-XXXXXX");
-		if (tmpdir == NULL) {
-			return NULL;
-		}
-
-		filename = camel_mime_part_get_filename (part);
-		if (filename == NULL) {
-			/* This is the default filename used for temporary file creation */
-			filename = _("Unknown");
-		} else {
-			utf8_mfilename = g_strdup (filename);
-			e_filename_make_safe (utf8_mfilename);
-			mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
-			g_free (utf8_mfilename);
-			filename = (const char *) mfilename;
-		}
-
-		path = g_build_filename(tmpdir, filename, NULL);
-		g_free(tmpdir);
-		g_free(mfilename);
-	} else if (!file) {
-		tmpdir = path;
-		filename = camel_mime_part_get_filename (part);
-		if (filename == NULL) {
-			/* This is the default filename used for temporary file creation */
-			filename = _("Unknown");
-		} else {
-			utf8_mfilename = g_strdup (filename);
-			e_filename_make_safe (utf8_mfilename);
-			mfilename = g_filename_from_utf8 ((const char *)utf8_mfilename, -1, NULL, NULL, NULL);
-			g_free (utf8_mfilename);
-			filename = (const char *) mfilename;
-		}
-
-		path = g_build_filename(tmpdir, filename, NULL);
-		g_free(mfilename);
-	}
-
-	if (strstr (path, "://"))
-		usepath = path;
-	else
-		usepath = g_strjoin (NULL, "file://", path, NULL);
-
-	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-	stream = camel_stream_vfs_new_with_uri (usepath, CAMEL_STREAM_VFS_CREATE);
-
-	if (usepath != path)
-		g_free (usepath);
-
-	if (!stream) {
-		/* TODO handle error conditions */
-		g_message ("DEBUG: could not open the file to write\n");
-		return NULL;
-	}
-
-	if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) {
-		camel_stream_close (stream);
-		camel_object_unref (stream);
-		g_message ("DEBUG: could not write to file\n");
-		return NULL;
-	}
-
-	camel_stream_close(stream);
-	camel_object_unref(stream);
-
-	return path;
-}
-
-static void
-ecalp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	EAttachment *attachment;
-	CamelMimePart *part = NULL;
-	char *file, *mfilename = NULL;
-	const char *filename;
-
-	attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) t)->attachments->data);
-	part = e_attachment_get_mime_part (attachment);
-	filename = camel_mime_part_get_filename (part);
-	if (filename == NULL) {
-		/* This is the default filename used for temporary file creation */
-		filename = _("Unknown");
-	} else {
-		mfilename = g_strdup(filename);
-		e_filename_make_safe(mfilename);
-		filename = mfilename;
-	}
-	file = e_file_dialog_save (_("Save As..."), filename);
-
-	if (file)
-		temp_save_part (part, file, TRUE);
-
-	g_free (file);
-	g_free (mfilename);
-}
-
-static void
-ecalp_part_popup_save_selected(EPopup *ep, EPopupItem *item, void *data)
-{
-	GSList *parts;
-	EPopupTarget *t = ep->target;
-	char *dir, *path;
-
-	dir = e_file_dialog_save_folder (_("Select folder to save selected attachments..."));
-	parts = ((ECalPopupTargetAttachments *) t)->attachments;
-
-	for (;parts; parts=parts->next) {
-		EAttachment *attachment = parts->data;
-		CamelMimePart *mime_part;
-
-		mime_part = e_attachment_get_mime_part (attachment);
-		path = temp_save_part (mime_part, dir, FALSE);
-		/* Probably we 'll do some reporting in next release, like listing the saved files and locations */
-		g_free (path);
-	}
-}
-
-static void
-ecalp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachment *attachment;
-	EPopupTarget *t = ep->target;
-	GConfClient *gconf;
-	char *str, *filename, *path, *extension;
-	unsigned int i=1;
-	CamelMimePart *part;
-
-	attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) t)->attachments->data);
-	part = e_attachment_get_mime_part (attachment);
-
-	if (!part)
-		return;
-
-	filename = g_strdup(camel_mime_part_get_filename(part));
-
-	/* if filename is blank, create a default filename based on MIME type */
-	if (!filename || !filename[0]) {
-		CamelContentType *ct;
-
-		ct = camel_mime_part_get_content_type(part);
-		g_free (filename);
-		filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype);
-	}
-
-	e_filename_make_safe(filename);
-
-	path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL);
-
-	extension = strrchr(filename, '.');
-	if (extension)
-		*extension++ = 0;
-
-	/* if file exists, stick a (number) on the end */
-	while (g_file_test(path, G_FILE_TEST_EXISTS)) {
-		char *name;
-		name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension);
-		g_free(path);
-		path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL);
-		g_free(name);
-	}
-
-	g_free(filename);
-
-	if (temp_save_part(part, path, TRUE)) {
-		gconf = gconf_client_get_default();
-
-		/* if the filename hasn't changed, blank the filename before
-		*  setting it so that gconf detects a change and updates it */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL
-		     && strcmp (str, path) == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL);
-		}
-
-		g_free (str);
-		gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL);
-
-		/* if GNOME currently doesn't display a picture, set to "wallpaper"
-		 * display mode, otherwise leave it alone */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL
-		     || strcmp(str, "none") == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL);
-		}
-
-		gconf_client_suggest_sync(gconf, NULL);
-
-		g_free(str);
-		g_object_unref(gconf);
-	}
-
-	g_free(path);
-}
-
-static const EPopupItem ecalp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
-
-static ECalPopupItem ecalp_attachment_object_popups[] = {
-	{ E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), ecalp_part_popup_saveas, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), ecalp_part_popup_set_background, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_IMAGE },
-	{ E_POPUP_ITEM, "00.attach.20", N_("_Save Selected"), ecalp_part_popup_save_selected, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_MULTIPLE },
-	{ E_POPUP_BAR, "05.attach", },
-};
-
-static void
-ecalp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
-{
-	char *path;
-	EAttachment *attachment;
-	EPopupTarget *target = ep->target;
-	CamelMimePart *part;
-
-	attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) target)->attachments->data);
-	part = e_attachment_get_mime_part (attachment);
-
-	path = temp_save_part(part, NULL, FALSE);
-	if (path) {
-		GAppInfo *app = item->user_data;
-		GList *uris = NULL;
-		GError *error = NULL;
-
-		if (g_app_info_supports_files (app)) {
-			GFile *file = g_file_new_for_path (path);
-
-			uris = g_list_append (uris, file);
-			g_app_info_launch (app, uris, NULL, &error);
-			g_object_unref (file);
-		} else {
-			char *uri;
-
-			uri = e_util_filename_to_uri (path);
-			uris = g_list_append (uris, uri);
-
-			g_app_info_launch_uris (app, uris, NULL, &error);
-			g_free (uri);
-		}
-
-		if (error) {
-			g_warning ("%s", error->message);
-			g_error_free (error);
-		}
-
-		g_list_free (uris);
-		g_free (path);
-	}
-}
-
-static void
-ecalp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
-{
-	while (free_list) {
-		GSList *n = free_list->next;
-		EPopupItem *item = free_list->data;
-
-		if (item->user_data && item->activate == ecalp_apps_open_in)
-			g_object_unref (item->user_data);
-
-		g_free(item->path);
-		g_free(item->label);
-		g_free(item);
-		g_slist_free_1(free_list);
-
-		free_list = n;
-	}
-}
-
-static void
-ecalp_standard_items_free(EPopup *ep, GSList *items, void *data)
-{
-	g_slist_free(items);
-}
-
-static void
-ecalp_standard_menu_factory (EPopup *ecalp, void *data)
-{
-	int i, len;
-	EPopupItem *items;
-	GSList *menus = NULL;
-	GList *apps = NULL;
-	char *mime_type = NULL;
-	const char *filename = NULL;
-
-	switch (ecalp->target->type) {
-	case E_CAL_POPUP_TARGET_ATTACHMENTS: {
-		ECalPopupTargetAttachments *t = (ECalPopupTargetAttachments *)ecalp->target;
-		GSList *list = t->attachments;
-		EAttachment *attachment;
-		CamelMimePart *mime_part;
-
-		items = ecalp_attachment_object_popups;
-		len = G_N_ELEMENTS(ecalp_attachment_object_popups);
-
-		if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
-			break;
-		}
-
-		/* Only one attachment selected */
-		attachment = list->data;
-		mime_part = e_attachment_get_mime_part (attachment);
-		mime_type = camel_data_wrapper_get_mime_type (CAMEL_DATA_WRAPPER (mime_part));
-		filename = camel_mime_part_get_filename (mime_part);
-
-
-		break; }
-	default:
-		items = NULL;
-		len = 0;
-	}
-
-	if (mime_type) {
-                gchar *cp;
-
-                /* does gvfs expect lowercase MIME types? */
-                for (cp = mime_type; *cp != '\0'; cp++)
-                        *cp = g_ascii_tolower (*cp);
-
-		cp = g_content_type_from_mime_type (mime_type);
-		apps = g_app_info_get_all_for_type (cp ? cp : mime_type);
-		g_free (cp);
-
-		if (apps == NULL && strcmp(mime_type, "application/octet-stream") == 0) {
-			if (filename) {
-				gchar *name_type;
-
-				name_type = e_util_guess_mime_type (filename, FALSE);
-				cp = g_content_type_from_mime_type (name_type);
-				apps = g_app_info_get_all_for_type (cp ? cp : name_type);
-				g_free (cp);
-				g_free (name_type);
-			}
-		}
-		g_free (mime_type);
-
-		if (apps) {
-			GSList *open_menus = NULL;
-			GList *l;
-
-			menus = g_slist_prepend(menus, (void *)&ecalp_standard_part_apps_bar);
-
-			for (l = apps, i = 0; l; l = l->next, i++) {
-				GAppInfo *app = l->data;
-				EPopupItem *item;
-
-				if (!g_app_info_should_show (app)) {
-					g_object_unref (app);
-					l->data = NULL;
-					continue;
-				}
-
-				item = g_malloc0(sizeof(*item));
-				item->type = E_POPUP_ITEM;
-				item->path = g_strdup_printf("99.object.%02d", i);
-				item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app));
-				item->activate = ecalp_apps_open_in;
-				item->user_data = app;
-
-				open_menus = g_slist_prepend(open_menus, item);
-			}
-
-			if (open_menus)
-				e_popup_add_items(ecalp, open_menus, NULL, ecalp_apps_popup_free, NULL);
-
-			g_list_free (apps);
-		}
-	}
-
-	for (i=0;i<len;i++) {
-		if ((items[i].visible & ecalp->target->mask) == 0)
-			menus = g_slist_prepend(menus, &items[i]);
-	}
-
-	if (menus)
-		e_popup_add_items(ecalp, menus, NULL, ecalp_standard_items_free, NULL);
-}
-
 static void
 ecalp_class_init(GObjectClass *klass)
 {
 	klass->finalize = ecalp_finalise;
 	((EPopupClass *)klass)->target_free = ecalp_target_free;
-
-	e_popup_class_add_factory((EPopupClass *)klass, NULL, ecalp_standard_menu_factory, NULL);
 }
 
 GType
@@ -763,64 +379,6 @@
 	return t;
 }
 
-/**
- * e_cal_popup_target_new_attachments:
- * @ecp:
- * @attachments: A list of CalAttachment objects, reffed for
- * the list.  Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-ECalPopupTargetAttachments *
-e_cal_popup_target_new_attachments(ECalPopup *ecp, CompEditor *editor, GSList *attachments)
-{
-	ECalPopupTargetAttachments *t = e_popup_target_new(&ecp->popup, E_CAL_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
-	guint32 mask = ~0;
-	int len = g_slist_length(attachments);
-	ECal *client = comp_editor_get_client (editor);
-	CompEditorFlags flags = comp_editor_get_flags (editor);
-	gboolean read_only = FALSE;
-	GError *error = NULL;
-
-	if (!e_cal_is_read_only (client, &read_only, &error)) {
-		if (error->code != E_CALENDAR_STATUS_BUSY)
-			read_only = TRUE;
-		g_error_free (error);
-	}
-
-	if (!read_only && (!(flags & COMP_EDITOR_MEETING) ||
-				(flags & COMP_EDITOR_NEW_ITEM) ||
-				(flags & COMP_EDITOR_USER_ORG)))
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MODIFY;
-
-	t->attachments = attachments;
-	if (len > 0)
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MANY;
-
-	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
-		EAttachment *attachment;
-		CamelMimePart *mime_part;
-		CamelContentType *mime_type;
-
-		attachment = attachments->data;
-		mime_part = e_attachment_get_mime_part (attachment);
-		mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type;
-
-		if (camel_content_type_is (mime_type, "image", "*"))
-			mask &= ~ E_CAL_POPUP_ATTACHMENTS_IMAGE;
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_ONE;
-	}
-
-	if (len > 1)
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MULTIPLE;
-
-	t->target.mask = mask;
-
-	return t;
-}
-
 /* ********************************************************************** */
 /* Popup menu plugin handler */
 

Modified: branches/kill-bonobo/composer/e-composer-actions.c
==============================================================================
--- branches/kill-bonobo/composer/e-composer-actions.c	(original)
+++ branches/kill-bonobo/composer/e-composer-actions.c	Fri Mar 20 19:06:59 2009
@@ -29,69 +29,13 @@
 action_attach_cb (GtkAction *action,
                   EMsgComposer *composer)
 {
-	EAttachmentBar *bar;
-	GtkWidget *dialog;
-	GtkWidget *option;
-	GSList *uris, *iter;
-	const gchar *disposition;
-	gboolean active;
-	gint response;
-
-	bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
+	EAttachmentView *view;
+	EAttachmentStore *store;
 
-	dialog = gtk_file_chooser_dialog_new (
-		_("Insert Attachment"),
-		GTK_WINDOW (composer),
-		GTK_FILE_CHOOSER_ACTION_OPEN,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		_("A_ttach"), GTK_RESPONSE_OK,
-		NULL);
-
-	gtk_dialog_set_default_response (
-		GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-	gtk_file_chooser_set_local_only (
-		GTK_FILE_CHOOSER (dialog), FALSE);
-	gtk_file_chooser_set_select_multiple (
-		GTK_FILE_CHOOSER (dialog), TRUE);
-	gtk_window_set_icon_name (
-		GTK_WINDOW (dialog), "mail-message-new");
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
-	option = gtk_check_button_new_with_mnemonic (
-		_("_Suggest automatic display of attachment"));
-	gtk_widget_show (option);
-	gtk_file_chooser_set_extra_widget (
-		GTK_FILE_CHOOSER (dialog), option);
-
-	response = gtkhtml_editor_file_chooser_dialog_run (
-		GTKHTML_EDITOR (composer), dialog);
-
-	if (response != GTK_RESPONSE_OK)
-		goto exit;
-
-	uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
-	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
-	disposition = active ? "inline" : "attachment";
-
-	for (iter = uris; iter != NULL; iter = iter->next) {
-		CamelURL *url;
-
-		url = camel_url_new (iter->data, NULL);
-		if (url == NULL)
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file"))
-			e_attachment_bar_attach (bar, url->path, disposition);
-		else
-			e_attachment_bar_attach_remote_file (bar, iter->data, disposition);
-
-		camel_url_free (url);
-	}
-
-	g_slist_foreach (uris, (GFunc) g_free, NULL);
-	g_slist_free (uris);
-
-exit:
-	gtk_widget_destroy (dialog);
+	e_attachment_store_run_load_dialog (store, GTK_WINDOW (composer));
 }
 
 static void
@@ -327,10 +271,10 @@
 action_new_message_cb (GtkAction *action,
                        EMsgComposer *composer)
 {
-	GtkWidget *widget;
+	EMsgComposer *new_composer;
 
-	widget = e_msg_composer_new ();
-	gtk_widget_show (widget);
+	new_composer = e_msg_composer_new ();
+	gtk_widget_show (GTK_WIDGET (new_composer));
 }
 
 static void

Modified: branches/kill-bonobo/composer/e-composer-private.c
==============================================================================
--- branches/kill-bonobo/composer/e-composer-private.c	(original)
+++ branches/kill-bonobo/composer/e-composer-private.c	Fri Mar 20 19:06:59 2009
@@ -51,22 +51,25 @@
 static void
 composer_setup_recent_menu (EMsgComposer *composer)
 {
+	EAttachmentView *view;
 	GtkUIManager *manager;
 	GtkAction *action = NULL;
-	const gchar *path, *action_name;
+	const gchar *action_name;
+	const gchar *path;
 	guint merge_id;
 
+	view = e_msg_composer_get_attachment_view (composer);
 	manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer));
-	action_name = "recent-menu";
 	path = "/main-menu/insert-menu/insert-menu-top/recent-placeholder";
 	merge_id = gtk_ui_manager_new_merge_id (manager);
+	action_name = "recent-menu";
 
-	action = e_attachment_bar_recent_action_new (
-			e_msg_composer_get_attachment_bar (composer), 
-			action_name, _("Recent _Documents"));
+	action = e_attachment_view_recent_action_new (
+		view, action_name, _("Recent _Documents"));
 
 	if (action != NULL) {
-		gtk_action_group_add_action (composer->priv->composer_actions, action);
+		gtk_action_group_add_action (
+			composer->priv->composer_actions, action);
 
 		gtk_ui_manager_add_ui ( 
 			manager, merge_id, path,
@@ -85,9 +88,8 @@
 
 	GtkhtmlEditor *editor;
 	GtkUIManager *manager;
-	GtkWidget *widget;
-	GtkWidget *expander;
 	GtkWidget *container;
+	GtkWidget *widget;
 	GtkWidget *send_widget;
 	const gchar *path;
 	gchar *filename;
@@ -138,66 +140,33 @@
 
 	/* Construct the header table. */
 
+	container = editor->vbox;
+
 	widget = e_composer_header_table_new ();
 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
-	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
-	gtk_box_reorder_child (GTK_BOX (editor->vbox), widget, 2);
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_box_reorder_child (GTK_BOX (container), widget, 2);
 	priv->header_table = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	/* Construct attachment widgets.
-	 * XXX Move this stuff into a new custom widget. */
+	/* Construct the attachment paned. */
 
-	widget = gtk_expander_new (NULL);
-	gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
+	widget = e_attachment_paned_new ();
 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
-	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
-	priv->attachment_expander = g_object_ref (widget);
-	gtk_widget_show (widget);
-	expander = widget;
-
-	widget = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (
-		GTK_SCROLLED_WINDOW (widget),
-		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (
-		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
-	gtk_container_add (GTK_CONTAINER (expander), widget);
-	priv->attachment_scrolled_window = g_object_ref (widget);
-	gtk_widget_show (widget);
-	container = widget;
-
-	widget = e_attachment_bar_new ();
-	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
-	gtk_container_add (GTK_CONTAINER (container), widget);
-	priv->attachment_bar = g_object_ref (widget);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->attachment_paned = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	widget = gtk_hbox_new (FALSE, 0);
-	gtk_expander_set_label_widget (GTK_EXPANDER (expander), widget);
-	gtk_widget_show (widget);
-	container = widget;
+	/* Reparent the scrolled window containing the GtkHTML widget
+	 * into the content area of the top attachment pane. */
 
-	widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar"));
-	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6);
-	priv->attachment_expander_label = g_object_ref (widget);
-	gtk_widget_show (widget);
-
-	widget = gtk_image_new_from_icon_name (
-		"mail-attachment", GTK_ICON_SIZE_MENU);
-	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
-	gtk_widget_set_size_request (widget, 100, -1);
-	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
-	priv->attachment_expander_icon = g_object_ref (widget);
-	gtk_widget_hide (widget);
-
-	widget = gtk_label_new (NULL);
-	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
-	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
-	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
-	priv->attachment_expander_num = g_object_ref (widget);
-	gtk_widget_show (widget);
+	widget = GTK_WIDGET (gtkhtml_editor_get_html (editor));
+	widget = gtk_widget_get_parent (widget);
+	container = e_attachment_paned_get_content_area (
+		E_ATTACHMENT_PANED (priv->attachment_paned));
+	gtk_widget_reparent (widget, container);
+	gtk_box_set_child_packing (
+		GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START);
 
 	composer_setup_recent_menu (composer);
 }
@@ -223,6 +192,11 @@
 		composer->priv->header_table = NULL;
 	}
 
+	if (composer->priv->attachment_paned != NULL) {
+		g_object_unref (composer->priv->attachment_paned);
+		composer->priv->attachment_paned = NULL;
+	}
+
 	if (composer->priv->charset_actions != NULL) {
 		g_object_unref (composer->priv->charset_actions);
 		composer->priv->charset_actions = NULL;

Modified: branches/kill-bonobo/composer/e-composer-private.h
==============================================================================
--- branches/kill-bonobo/composer/e-composer-private.h	(original)
+++ branches/kill-bonobo/composer/e-composer-private.h	Fri Mar 20 19:06:59 2009
@@ -25,13 +25,14 @@
 
 #include <camel/camel-iconv.h>
 
-#include "e-attachment-bar.h"
 #include "e-composer-actions.h"
 #include "e-composer-autosave.h"
 #include "e-composer-header-table.h"
 #include "e-util/e-binding.h"
 #include "e-util/e-util.h"
 #include "e-util/gconf-bridge.h"
+#include "widgets/misc/e-attachment-paned.h"
+#include "widgets/misc/e-attachment-store.h"
 
 #define E_MSG_COMPOSER_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -94,6 +95,8 @@
 
 	GtkWidget *html_editor;
 	GtkWidget *header_table;
+	GtkWidget *attachment_paned;
+
 	GtkActionGroup *charset_actions;
 	GtkActionGroup *composer_actions;
 
@@ -102,13 +105,6 @@
 
 	GtkWidget *focused_entry;
 
-	GtkWidget *attachment_bar;
-	GtkWidget *attachment_scrolled_window;
-	GtkWidget *attachment_expander;
-	GtkWidget *attachment_expander_label;
-	GtkWidget *attachment_expander_icon;
-	GtkWidget *attachment_expander_num;
-
 	GtkWidget *address_dialog;
 
 	GHashTable *inline_images;
@@ -117,7 +113,6 @@
 
 	gchar *mime_type, *mime_body, *charset;
 
-	guint32 attachment_bar_visible : 1;
 	guint32 is_alternative         : 1;
 	guint32 autosaved              : 1;
 	guint32 mode_post              : 1;

Modified: branches/kill-bonobo/composer/e-msg-composer.c
==============================================================================
--- branches/kill-bonobo/composer/e-msg-composer.c	(original)
+++ branches/kill-bonobo/composer/e-msg-composer.c	Fri Mar 20 19:06:59 2009
@@ -76,13 +76,11 @@
 #include <camel/camel-smime-context.h>
 #endif
 
-#include "mail/em-popup.h"
 #include "mail/em-utils.h"
 #include "mail/mail-tools.h"
 
 #include "e-msg-composer.h"
 #include "e-attachment.h"
-#include "e-attachment-bar.h"
 #include "e-composer-autosave.h"
 #include "e-composer-private.h"
 #include "e-composer-header-table.h"
@@ -178,7 +176,6 @@
 static GList *add_recipients (GList *list, const gchar *recips);
 
 static void handle_mailto (EMsgComposer *composer, const gchar *mailto);
-static void handle_uri    (EMsgComposer *composer, const gchar *uri, gboolean html_dnd);
 
 /* used by e_msg_composer_add_message_attachments () */
 static void add_attachments_from_multipart (EMsgComposer *composer, CamelMultipart *multipart,
@@ -510,7 +507,8 @@
 	GtkhtmlEditor *editor;
 	EMsgComposerPrivate *p = composer->priv;
 
-	EAttachmentBar *attachment_bar;
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
 	GtkToggleAction *action;
 	CamelDataWrapper *plain, *html, *current;
@@ -538,7 +536,8 @@
 	editor = GTKHTML_EDITOR (composer);
 	table = e_msg_composer_get_header_table (composer);
 	account = e_composer_header_table_get_account (table);
-	attachment_bar = E_ATTACHMENT_BAR (p->attachment_bar);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 	session = e_msg_composer_get_session (composer);
 
 	/* evil kludgy hack for Redirect */
@@ -699,7 +698,7 @@
 	} else
 		current = plain;
 
-	if (e_attachment_bar_get_num_attachments (attachment_bar)) {
+	if (e_attachment_store_get_num_attachments (store) > 0) {
 		CamelMultipart *multipart = camel_multipart_new ();
 
 		if (p->is_alternative) {
@@ -718,7 +717,8 @@
 		camel_multipart_add_part (multipart, part);
 		camel_object_unref (part);
 
-		e_attachment_bar_to_multipart (attachment_bar, multipart, p->charset);
+		e_attachment_store_add_to_multipart (
+			store, multipart, p->charset);
 
 		if (p->is_alternative) {
 			for (i = camel_multipart_get_number (multipart); i > 1; i--) {
@@ -1252,65 +1252,17 @@
 /* Miscellaneous callbacks.  */
 
 static void
-attachment_bar_changed_cb (EAttachmentBar *attachment_bar,
-                           EMsgComposer *composer)
+attachment_store_changed_cb (EMsgComposer *composer)
 {
 	GtkhtmlEditor *editor;
-	GtkWidget *widget;
-	guint attachment_num;
-
-	editor = GTKHTML_EDITOR (composer);
-	attachment_num = e_attachment_bar_get_num_attachments (attachment_bar);
-
-	if (attachment_num > 0) {
-		gchar *markup;
-
-		markup = g_strdup_printf (
-			"<b>%d</b> %s", attachment_num, ngettext (
-			"Attachment", "Attachments", attachment_num));
-		widget = composer->priv->attachment_expander_num;
-		gtk_label_set_markup (GTK_LABEL (widget), markup);
-		g_free (markup);
-
-		gtk_widget_show (composer->priv->attachment_expander_icon);
-
-		widget = composer->priv->attachment_expander;
-		gtk_expander_set_expanded (GTK_EXPANDER (widget), TRUE);
-	} else {
-		widget = composer->priv->attachment_expander_num;
-		gtk_label_set_text (GTK_LABEL (widget), "");
-
-		gtk_widget_hide (composer->priv->attachment_expander_icon);
-
-		widget = composer->priv->attachment_expander;
-		gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
-	}
 
 	/* Mark the editor as changed so it prompts about unsaved
 	   changes on close. */
+	editor = GTKHTML_EDITOR (composer);
 	gtkhtml_editor_set_changed (editor, TRUE);
 }
 
 static void
-attachment_expander_notify_cb (GtkExpander *expander,
-                               GParamSpec *pspec,
-                               EMsgComposer *composer)
-{
-	GtkLabel *label;
-	const gchar *text;
-
-	label = GTK_LABEL (composer->priv->attachment_expander_label);
-
-	/* Update the expander label */
-	if (gtk_expander_get_expanded (expander))
-		text = _("Hide _Attachment Bar");
-	else
-		text = _("Show _Attachment Bar");
-
-	gtk_label_set_text_with_mnemonic (label, text);
-}
-
-static void
 msg_composer_subject_changed_cb (EMsgComposer *composer)
 {
 	EComposerHeaderTable *table;
@@ -1505,35 +1457,6 @@
 	g_object_unref (iterator);
 }
 
-static void
-msg_composer_attach_message (EMsgComposer *composer,
-                             CamelMimeMessage *msg)
-{
-	CamelMimePart *mime_part;
-	GString *description;
-	const gchar *subject;
-	EMsgComposerPrivate *p = composer->priv;
-
-	mime_part = camel_mime_part_new ();
-	camel_mime_part_set_disposition (mime_part, "inline");
-	subject = camel_mime_message_get_subject (msg);
-
-	description = g_string_new (_("Attached message"));
-	if (subject != NULL)
-		g_string_append_printf (description, " - %s", subject);
-	camel_mime_part_set_description (mime_part, description->str);
-	g_string_free (description, TRUE);
-
-	camel_medium_set_content_object (
-		(CamelMedium *) mime_part, (CamelDataWrapper *) msg);
-	camel_mime_part_set_content_type (mime_part, "message/rfc822");
-
-	e_attachment_bar_attach_mime_part (
-		E_ATTACHMENT_BAR (p->attachment_bar), mime_part);
-
-	camel_object_unref (mime_part);
-}
-
 struct _drop_data {
 	EMsgComposer *composer;
 
@@ -1544,23 +1467,9 @@
 	guint32 action;
 	guint info;
 	guint time;
-
-	unsigned int move:1;
-	unsigned int moved:1;
-	unsigned int aborted:1;
 };
 
-int
-e_msg_composer_get_remote_download_count (EMsgComposer *composer)
-{
-	EAttachmentBar *attachment_bar;
-
-	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), 0);
-
-	attachment_bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-	return e_attachment_bar_get_download_count (attachment_bar);
-}
-
+#if 0  /* KILL-BONOBO */
 static void
 drop_action (EMsgComposer *composer,
              GdkDragContext *context,
@@ -1570,77 +1479,12 @@
              guint time,
              gboolean html_dnd)
 {
-	char *tmp, *str, **urls;
 	CamelMimePart *mime_part;
-	CamelStream *stream;
 	CamelMimeMessage *msg;
-	char *content_type;
 	int i, success = FALSE, delete = FALSE;
 	EMsgComposerPrivate *p = composer->priv;
 
 	switch (info) {
-	case DND_TYPE_MESSAGE_RFC822:
-		d (printf ("dropping a message/rfc822\n"));
-		/* write the message (s) out to a CamelStream so we can use it */
-		stream = camel_stream_mem_new ();
-		camel_stream_write (stream, (const gchar *)selection->data, selection->length);
-		camel_stream_reset (stream);
-
-		msg = camel_mime_message_new ();
-		if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *)msg, stream) != -1) {
-			msg_composer_attach_message (composer, msg);
-			success = TRUE;
-			delete = action == GDK_ACTION_MOVE;
-		}
-
-		camel_object_unref (msg);
-		camel_object_unref (stream);
-		break;
-	case DND_TYPE_NETSCAPE_URL:
-		d (printf ("dropping a _NETSCAPE_URL\n"));
-		tmp = g_strndup ((const gchar *) selection->data, selection->length);
-		urls = g_strsplit (tmp, "\n", 2);
-		g_free (tmp);
-
-		/* _NETSCAPE_URL is represented as "URI\nTITLE" */
-		handle_uri (composer, urls[0], html_dnd);
-
-		g_strfreev (urls);
-		success = TRUE;
-		break;
-	case DND_TYPE_TEXT_URI_LIST:
-		d (printf ("dropping a text/uri-list\n"));
-		tmp = g_strndup ((const gchar *) selection->data, selection->length);
-		urls = g_strsplit (tmp, "\n", 0);
-		g_free (tmp);
-
-		for (i = 0; urls[i] != NULL; i++) {
-			str = g_strstrip (urls[i]);
-			if (str[0] == '#' || str[0] == '\0')
-				continue;
-
-			handle_uri (composer, str, html_dnd);
-		}
-
-		g_strfreev (urls);
-		success = TRUE;
-		break;
-	case DND_TYPE_TEXT_VCARD:
-	case DND_TYPE_TEXT_CALENDAR:
-		content_type = gdk_atom_name (selection->type);
-		d (printf ("dropping a %s\n", content_type));
-
-		mime_part = camel_mime_part_new ();
-		camel_mime_part_set_content (mime_part, (const gchar *)selection->data, selection->length, content_type);
-		camel_mime_part_set_disposition (mime_part, "inline");
-
-		e_attachment_bar_attach_mime_part (E_ATTACHMENT_BAR (p->attachment_bar), mime_part);
-
-		camel_object_unref (mime_part);
-		g_free (content_type);
-
-		success = TRUE;
-		break;
 	case DND_TYPE_X_UID_LIST: {
 		GPtrArray *uids;
 		char *inptr, *inend;
@@ -1734,55 +1578,7 @@
 
 	gtk_drag_finish (context, success, delete, time);
 }
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	drop_action (
-		m->composer, m->context, GDK_ACTION_COPY,
-		m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	drop_action (
-		m->composer, m->context, GDK_ACTION_MOVE,
-		m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_cancel (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	gtk_drag_finish (m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
-	{ E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
-	{ E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
-	{ E_POPUP_BAR, "10.emc" },
-	{ E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free (EPopup *ep, GSList *items, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	g_slist_free (items);
-
-	g_object_unref (m->context);
-	g_object_unref (m->composer);
-	g_free (m->selection->data);
-	g_free (m->selection);
-	g_free (m);
-}
+#endif
 
 static void
 msg_composer_notify_header_cb (EMsgComposer *composer)
@@ -2022,33 +1818,14 @@
                           gint y,
                           guint time)
 {
-	GList *targets;
-	GdkDragAction actions = 0;
-	GdkDragAction chosen_action;
-
-	targets = context->targets;
-	while (targets != NULL) {
-		gint ii;
-
-		for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
-			if (targets->data == (gpointer) drag_info[ii].atom)
-				actions |= drag_info[ii].actions;
-
-		targets = g_list_next (targets);
-	}
-
-	actions &= context->actions;
-	chosen_action = context->suggested_action;
-
-	/* we default to copy */
-	if (chosen_action == GDK_ACTION_ASK &&
-		(actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) !=
-		(GDK_ACTION_MOVE|GDK_ACTION_COPY))
-		chosen_action = GDK_ACTION_COPY;
+	EMsgComposer *composer;
+	EAttachmentView *view;
 
-	gdk_drag_status (context, chosen_action, time);
+	/* Widget may be EMsgComposer or GtkHTML. */
+	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
+	view = e_msg_composer_get_attachment_view (composer);
 
-	return (chosen_action != 0);
+	return e_attachment_view_drag_motion (view, context, x, y, time);
 }
 
 static void
@@ -2061,46 +1838,14 @@
                                  guint time)
 {
 	EMsgComposer *composer;
+	EAttachmentView *view;
 
 	/* Widget may be EMsgComposer or GtkHTML. */
 	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
+	view = e_msg_composer_get_attachment_view (composer);
 
-	if (selection->data == NULL)
-		return;
-
-	if (selection->length == -1)
-		return;
-
-	if (context->action == GDK_ACTION_ASK) {
-		EMPopup *emp;
-		GSList *menus = NULL;
-		GtkMenu *menu;
-		gint ii;
-		struct _drop_data *m;
-
-		m = g_malloc0(sizeof (*m));
-		m->context = g_object_ref (context);
-		m->composer = g_object_ref (composer);
-		m->action = context->action;
-		m->info = info;
-		m->time = time;
-		m->selection = g_malloc0(sizeof (*m->selection));
-		m->selection->data = g_malloc (selection->length);
-		memcpy (m->selection->data, selection->data, selection->length);
-		m->selection->length = selection->length;
-
-		emp = em_popup_new ("org.gnome.evolution.mail.composer.popup.drop");
-		for (ii = 0; ii < G_N_ELEMENTS (drop_popup_menu); ii++)
-			menus = g_slist_append (menus, &drop_popup_menu[ii]);
-
-		e_popup_add_items ((EPopup *)emp, menus, NULL, drop_popup_free, m);
-		menu = e_popup_create_menu_once ((EPopup *)emp, NULL, 0);
-		gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, time);
-	} else {
-		drop_action (
-			composer, context, context->action, selection,
-			info, time, !GTK_WIDGET_TOPLEVEL (widget));
-	}
+	e_attachment_view_drag_data_received (
+		view, context, x, y, selection, info, time);
 }
 
 static void
@@ -2147,11 +1892,21 @@
 msg_composer_paste_clipboard (GtkhtmlEditor *editor)
 {
 	EMsgComposer *composer;
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	GtkClipboard *clipboard;
+	GdkPixbuf *pixbuf;
 	GtkWidget *parent;
 	GtkWidget *widget;
-	GtkClipboard *clipboard;
+	gchar *filename;
+	gchar *uri;
+	gint fd;
+	GError *error = NULL;
 
 	composer = E_MSG_COMPOSER (editor);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
 	widget = gtk_window_get_focus (GTK_WINDOW (editor));
 	parent = gtk_widget_get_parent (widget);
 
@@ -2161,36 +1916,61 @@
 	}
 
 	clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
-	if (clipboard && gtk_clipboard_wait_is_image_available (clipboard)) {
-		GdkPixbuf *pixbuf;
 
-		pixbuf = gtk_clipboard_wait_for_image (clipboard);
-		if (pixbuf) {
-			char *tmpl = g_strconcat (_("Image"), "-XXXXXX", NULL);
-			char *filename = e_mktemp (tmpl);
-
-			g_free (tmpl);
-
-			if (filename && gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL)) {
-				if (gtkhtml_editor_get_html_mode (editor)) {
-					char *uri = g_strconcat ("file://", filename, NULL);
-					/* this loads image async, thus cannot remove file from this */
-					gtkhtml_editor_insert_image (editor, uri);
-					g_free (uri);
-				} else {
-					/* this loads image immediately, remove file from cache to free up disk space */
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (composer->priv->attachment_bar), filename, "image/png");
-					g_remove (filename);
-				}
-			}
+	/* Assume the clipboard has an image.  The return
+	 * value will be NULL if we assumed wrong. */
+	pixbuf = gtk_clipboard_wait_for_image (clipboard);
+	if (!GDK_IS_PIXBUF (pixbuf))
+		goto chainup;
 
-			g_free (filename);
-			g_object_unref (pixbuf);
-		}
-	} else {
-		/* Chain up to parent's paste_clipboard() method. */
-		GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
+	/* Reserve a temporary file. */
+	fd = e_file_open_tmp (&filename, &error);
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		return;
+	}
+	close (fd);
+
+	/* Save the pixbuf as a temporary file in image/png format. */
+	if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) {
+		g_warning ("%s", error->message);
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		g_free (filename);
+		return;
+	}
+
+	/* Convert the filename to a URI. */
+	uri = g_filename_to_uri (filename, NULL, &error);
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		g_free (filename);
+		return;
+	}
+
+	if (gtkhtml_editor_get_html_mode (editor))
+		gtkhtml_editor_insert_image (editor, uri);
+	else {
+		EAttachment *attachment;
+
+		attachment = e_attachment_new_for_uri (uri);
+		e_attachment_store_add_attachment (store, attachment);
+		g_object_unref (attachment);
 	}
+
+	g_object_unref (pixbuf);
+	g_free (filename);
+	g_free (uri);
+
+	return;
+
+chainup:
+	/* Chain up to parent's paste_clipboard() method. */
+	GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
 }
 
 static void
@@ -2479,6 +2259,8 @@
 static void
 msg_composer_init (EMsgComposer *composer)
 {
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
 	GtkUIManager *manager;
 	GtkhtmlEditor *editor;
@@ -2505,27 +2287,6 @@
 		drop_types, G_N_ELEMENTS (drop_types),
 		GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
 
-	/* XXX I'm not sure why we have to explicitly configure the
-	 *     attachment bar as a drag destination when CompEditor
-	 *     doesn't and previous Evolution releases (2.22 and
-	 *     prior) don't, but this is the only way I could figure
-	 *     out how to get drag-and-drop to the attachment bar
-	 *     working again.  I'm probably overlooking something
-	 *     simple... */
-
-	gtk_drag_dest_set (
-		composer->priv->attachment_bar, GTK_DEST_DEFAULT_ALL,
-		drop_types, G_N_ELEMENTS (drop_types),
-		GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
-
-	g_signal_connect (
-		composer->priv->attachment_bar, "drag-motion",
-		G_CALLBACK (msg_composer_drag_motion), NULL);
-
-	g_signal_connect (
-		composer->priv->attachment_bar, "drag-data-received",
-		G_CALLBACK (msg_composer_drag_data_received), NULL);
-
 	g_signal_connect (
 		html, "drag-data-received",
 		G_CALLBACK (msg_composer_drag_data_received), NULL);
@@ -2568,14 +2329,18 @@
 	msg_composer_account_changed_cb (composer);
 	msg_composer_account_list_changed_cb (composer);
 
-	/* Attachment Bar */
+	/* Attachments */
 
-	g_signal_connect (
-		composer->priv->attachment_bar, "changed",
-		G_CALLBACK (attachment_bar_changed_cb), composer);
-	g_signal_connect_after (
-		composer->priv->attachment_expander, "notify::expanded",
-		G_CALLBACK (attachment_expander_notify_cb), composer);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
+	g_signal_connect_swapped (
+		store, "row-deleted",
+		G_CALLBACK (attachment_store_changed_cb), composer);
+
+	g_signal_connect_swapped (
+		store, "row-inserted",
+		G_CALLBACK (attachment_store_changed_cb), composer);
 
 	e_composer_autosave_register (composer);
 
@@ -3445,7 +3210,7 @@
 	action = GTKHTML_EDITOR_ACTION_INSERT_MENU (composer);
 	gtk_action_set_sensitive (action, FALSE);
 
-	gtk_widget_set_sensitive (composer->priv->attachment_bar, FALSE);
+	gtk_widget_set_sensitive (composer->priv->attachment_paned, FALSE);
 }
 
 /**
@@ -3589,7 +3354,8 @@
 static void
 handle_mailto (EMsgComposer *composer, const gchar *mailto)
 {
-	EMsgComposerPrivate *priv = composer->priv;
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
 	GList *to = NULL, *cc = NULL, *bcc = NULL;
 	EDestination **tov, **ccv, **bccv;
@@ -3598,9 +3364,10 @@
 	gsize nread, nwritten;
 	const gchar *p;
 	gint len, clen;
-	CamelURL *url;
 
 	table = e_msg_composer_get_header_table (composer);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
 	buf = g_strdup (mailto);
 
@@ -3672,20 +3439,11 @@
 				}
 			} else if (!g_ascii_strcasecmp (header, "attach") ||
 				   !g_ascii_strcasecmp (header, "attachment")) {
-				/* Change file url to absolute path */
-				if (!g_ascii_strncasecmp (content, "file:", 5)) {
-					url = camel_url_new (content, NULL);
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
-							 	 url->path,
-								 "attachment");
-					camel_url_free (url);
-				} else {
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
-								 content,
-								 "attachment");
-				}
-				gtk_widget_show (priv->attachment_expander);
-				gtk_widget_show (priv->attachment_scrolled_window);
+				EAttachment *attachment;
+
+				attachment = e_attachment_new_for_uri (content);
+				e_attachment_store_add_attachment (store, attachment);
+				g_object_unref (attachment);
 			} else if (!g_ascii_strcasecmp (header, "from")) {
 				/* Ignore */
 			} else if (!g_ascii_strcasecmp (header, "reply-to")) {
@@ -3737,45 +3495,6 @@
 	}
 }
 
-static void
-handle_uri (EMsgComposer *composer,
-            const gchar *uri,
-            gboolean html_dnd)
-{
-	EMsgComposerPrivate *p = composer->priv;
-	GtkhtmlEditor *editor;
-	gboolean html_content;
-
-	editor = GTKHTML_EDITOR (composer);
-	html_content = gtkhtml_editor_get_html_mode (editor);
-
-	if (!g_ascii_strncasecmp (uri, "mailto:";, 7)) {
-		handle_mailto (composer, uri);
-	} else {
-		CamelURL *url = camel_url_new (uri, NULL);
-		gchar *type;
-
-		if (!url)
-			return;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file")) {
-			type = e_util_guess_mime_type (uri + strlen ("file://"), TRUE);
-			if (!type)
-				return;
-
-			if (strncmp (type, "image", 5) || !html_dnd || (!html_content && !strncmp (type, "image", 5))) {
-				e_attachment_bar_attach (E_ATTACHMENT_BAR (p->attachment_bar),
-						url->path, "attachment");
-			}
-			g_free (type);
-		} else	{
-			e_attachment_bar_attach_remote_file (E_ATTACHMENT_BAR (p->attachment_bar),
-					uri, "attachment");
-		}
-		camel_url_free (url);
-	}
-}
-
 /**
  * e_msg_composer_new_from_url:
  * @url: a mailto URL
@@ -3939,21 +3658,28 @@
 /**
  * e_msg_composer_attach:
  * @composer: a composer object
- * @attachment: the CamelMimePart to attach
+ * @mime_part: the #CamelMimePart to attach
  *
  * Attaches @attachment to the message being composed in the composer.
  **/
 void
-e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment)
+e_msg_composer_attach (EMsgComposer *composer,
+                       CamelMimePart *mime_part)
 {
-	EAttachmentBar *bar;
-	EMsgComposerPrivate *p = composer->priv;
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	EAttachment *attachment;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-	g_return_if_fail (CAMEL_IS_MIME_PART (attachment));
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
-	bar = E_ATTACHMENT_BAR (p->attachment_bar);
-	e_attachment_bar_attach_mime_part (bar, attachment);
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
+	e_attachment_store_add_attachment (store, attachment);
+	g_object_unref (attachment);
 }
 
 /**
@@ -4067,12 +3793,17 @@
 e_msg_composer_get_message (EMsgComposer *composer,
                             gboolean save_html_object_data)
 {
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	GtkhtmlEditor *editor;
 	gboolean html_content;
 
 	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
 
-	if (e_msg_composer_get_remote_download_count (composer) != 0) {
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
+	if (e_attachment_store_get_num_downloading (store) > 0) {
 		if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL,
 			"mail-composer:ask-send-message-pending-download", NULL)) {
 			return NULL;
@@ -4367,14 +4098,6 @@
 	return array;
 }
 
-EAttachmentBar *
-e_msg_composer_get_attachment_bar (EMsgComposer *composer)
-{
-	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
-
-	return E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-}
-
 void
 e_msg_composer_set_enable_autosave (EMsgComposer *composer,
                                     gboolean enabled)
@@ -4529,6 +4252,18 @@
 	return E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
 }
 
+EAttachmentView *
+e_msg_composer_get_attachment_view (EMsgComposer *composer)
+{
+	EAttachmentPaned *paned;
+
+	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+	paned = E_ATTACHMENT_PANED (composer->priv->attachment_paned);
+
+	return e_attachment_paned_get_view (paned);
+}
+
 void
 e_msg_composer_set_send_options (EMsgComposer *composer,
                                  gboolean send_enable)

Modified: branches/kill-bonobo/composer/e-msg-composer.h
==============================================================================
--- branches/kill-bonobo/composer/e-msg-composer.h	(original)
+++ branches/kill-bonobo/composer/e-msg-composer.h	Fri Mar 20 19:06:59 2009
@@ -29,6 +29,7 @@
 #include <libedataserver/e-account.h>
 #include <libebook/e-destination.h>
 #include <gtkhtml-editor.h>
+#include <widgets/misc/e-attachment-view.h>
 
 #include "e-composer-header-table.h"
 
@@ -66,8 +67,6 @@
 	GtkhtmlEditorClass parent_class;
 };
 
-struct _EAttachmentBar;
-
 #define E_MSG_COMPOSER_MAIL 1
 #define E_MSG_COMPOSER_POST 2
 #define E_MSG_COMPOSER_MAIL_POST E_MSG_COMPOSER_MAIL|E_MSG_COMPOSER_POST
@@ -104,7 +103,7 @@
 void		e_msg_composer_remove_header	(EMsgComposer *composer,
 						 const gchar *name);
 void		e_msg_composer_attach		(EMsgComposer *composer,
-						 CamelMimePart *attachment);
+						 CamelMimePart *mime_part);
 CamelMimePart *	e_msg_composer_add_inline_image_from_file
 						(EMsgComposer *composer,
 						 const gchar *filename);
@@ -140,22 +139,19 @@
 gboolean	e_msg_composer_request_close_all(void);
 EMsgComposer *	e_msg_composer_load_from_file	(const gchar *filename);
 void		e_msg_composer_check_autosave	(GtkWindow *parent);
-gint		e_msg_composer_get_remote_download_count
-						(EMsgComposer *composer);
 
 void		e_msg_composer_reply_indent	(EMsgComposer *composer);
 
 EComposerHeaderTable *
 		e_msg_composer_get_header_table	(EMsgComposer *composer);
+EAttachmentView *
+		e_msg_composer_get_attachment_view
+						(EMsgComposer *composer);
 void		e_msg_composer_set_send_options	(EMsgComposer *composer,
 						 gboolean send_enable);
 GByteArray *	e_msg_composer_get_raw_message_text
 						(EMsgComposer *composer);
 
-struct _EAttachmentBar *
-		e_msg_composer_get_attachment_bar
-						(EMsgComposer *composer);
-
 gboolean	e_msg_composer_is_exiting	(EMsgComposer *composer);
 
 GList *		e_load_spell_languages		(void);

Modified: branches/kill-bonobo/e-util/Makefile.am
==============================================================================
--- branches/kill-bonobo/e-util/Makefile.am	(original)
+++ branches/kill-bonobo/e-util/Makefile.am	Fri Mar 20 19:06:59 2009
@@ -34,7 +34,7 @@
 	-DSEARCH_RULE_DIR=\"$(ruledir)\"				\
 	-DG_LOG_DOMAIN=\"e-utils\"					\
 	$(GNOME_PILOT_CFLAGS)						\
-	$(ICONV_CFLAGS)                        				\
+	$(ICONV_CFLAGS)							\
 	$(E_UTIL_CFLAGS)
 
 privsolib_LTLIBRARIES = libeutil.la libeconduit.la

Modified: branches/kill-bonobo/e-util/e-util.c
==============================================================================
--- branches/kill-bonobo/e-util/e-util.c	(original)
+++ branches/kill-bonobo/e-util/e-util.c	Fri Mar 20 19:06:59 2009
@@ -1529,23 +1529,32 @@
 	return res;
 }
 
-GSList *
-e_util_get_category_filter_options (void)
+static gpointer
+e_camel_object_copy (gpointer camel_object)
 {
-	GSList *res = NULL;
-	GList *clist, *l;
+	if (CAMEL_IS_OBJECT (camel_object))
+		camel_object_ref (camel_object);
 
-	clist = e_categories_get_list ();
-	for (l = clist; l; l = l->next) {
-		const char *cname = l->data;
-		struct _filter_option *fo = g_new0 (struct _filter_option, 1);
-
-		fo->title = g_strdup (cname);
-		fo->value = g_strdup (cname);
-		res = g_slist_prepend (res, fo);
-	}
+	return camel_object;
+}
+
+static void
+e_camel_object_free (gpointer camel_object)
+{
+	if (CAMEL_IS_OBJECT (camel_object))
+		camel_object_unref (camel_object);
+}
+
+GType
+e_camel_object_get_type (void)
+{
+	static GType type = 0;
 
-	g_list_free (clist);
+	if (G_UNLIKELY (type == 0))
+		type = g_boxed_type_register_static (
+			"ECamelObject",
+			(GBoxedCopyFunc) e_camel_object_copy,
+			(GBoxedFreeFunc) e_camel_object_free);
 
-	return g_slist_reverse (res);
+	return type;
 }

Modified: branches/kill-bonobo/e-util/e-util.h
==============================================================================
--- branches/kill-bonobo/e-util/e-util.h	(original)
+++ branches/kill-bonobo/e-util/e-util.h	Fri Mar 20 19:06:59 2009
@@ -27,6 +27,7 @@
 #include <gtk/gtk.h>
 #include <limits.h>
 #include <gconf/gconf-client.h>
+#include <camel/camel-object.h>
 #include <cairo.h>
 
 #include <e-util/e-marshal.h>
@@ -131,7 +132,8 @@
 void		e_file_lock_destroy		(void);
 gboolean 	e_file_lock_exists		(void);
 
-gchar *		e_util_guess_mime_type		(const gchar *filename, gboolean localfile);
+gchar *		e_util_guess_mime_type		(const gchar *filename,
+                                                 gboolean localfile);
 gchar *		e_util_filename_to_uri		(const gchar *filename);
 gchar *		e_util_uri_to_filename		(const gchar *uri);
 
@@ -141,7 +143,10 @@
 						 gsize *read,
 						 GError **error);
 
-GSList *e_util_get_category_filter_options      (void);
+/* Camel uses its own object system, so we have to box
+ * CamelObjects to safely use them as GObject properties. */
+#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ())
+GType		e_camel_object_get_type		(void);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/mail/e-mail-browser.c
==============================================================================
--- branches/kill-bonobo/mail/e-mail-browser.c	(original)
+++ branches/kill-bonobo/mail/e-mail-browser.c	Fri Mar 20 19:06:59 2009
@@ -653,7 +653,7 @@
 		static const GInterfaceInfo iface_info = {
 			(GInterfaceInitFunc) mail_browser_iface_init,
 			(GInterfaceFinalizeFunc) NULL,
-			NULL  /* interface_data */
+			NULL   /* interface_data */
 		};
 
 		type = g_type_register_static (

Modified: branches/kill-bonobo/mail/e-mail-reader.c
==============================================================================
--- branches/kill-bonobo/mail/e-mail-reader.c	(original)
+++ branches/kill-bonobo/mail/e-mail-reader.c	Fri Mar 20 19:06:59 2009
@@ -2009,7 +2009,7 @@
 			NULL,  /* class_data */
 			0,     /* instance_size */
 			0,     /* n_preallocs */
-			NULL,  /* instance_init */
+			(GInstanceInitFunc) NULL,
 			NULL   /* value_table */
 		};
 

Modified: branches/kill-bonobo/mail/em-format-html-display.c
==============================================================================
--- branches/kill-bonobo/mail/em-format-html-display.c	(original)
+++ branches/kill-bonobo/mail/em-format-html-display.c	Fri Mar 20 19:06:59 2009
@@ -79,8 +79,8 @@
 #include "em-icon-stream.h"
 #include "em-utils.h"
 #include "em-popup.h"
-#include "e-attachment.h"
-#include "e-attachment-bar.h"
+#include "widgets/misc/e-attachment-view.h"
+#include "widgets/misc/e-attachment-icon-view.h"
 
 #ifdef G_OS_WIN32
 /* Undefine the similar macro from <pthread.h>,it doesn't check if
@@ -100,7 +100,7 @@
 
 struct _EMFormatHTMLDisplayPrivate {
 	/* for Attachment bar */
-	GtkWidget *attachment_bar;
+	GtkWidget *attachment_view;
 	GtkWidget *attachment_box;
 	GtkWidget *label;
 	GtkWidget *save_txt;
@@ -494,8 +494,8 @@
 	info->shown = em_format_is_inline (
 		emf, info->puri.part_id, info->puri.part, handle);
 	info->snoop_mime_type = emf->snoop_mime_type;
-	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
-	e_attachment_bar_create_attachment_cache (info->attachment);
+	info->attachment = e_attachment_new ();
+	e_attachment_set_mime_part (info->attachment, info->puri.part);
 
 	if (emf->valid) {
 		info->sign = emf->valid->sign.status;
@@ -559,7 +559,8 @@
 	info->handle = em_format_find_handler (emf, "text/plain");
 	info->shown = FALSE;
 	info->snoop_mime_type = "text/plain";
-	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
+	info->attachment = e_attachment_new ();
+	e_attachment_set_mime_part (info->attachment, info->puri.part);
 	info->mstream = (CamelStreamMem *) mstream;
 	if (emf->valid) {
 		info->sign = emf->valid->sign.status;
@@ -736,12 +737,6 @@
 	return g_object_new (EM_TYPE_FORMAT_HTML_DISPLAY, NULL);
 }
 
-EAttachmentBar *
-em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd)
-{
-	return E_ATTACHMENT_BAR (efhd->priv->attachment_bar);
-}
-
 void
 em_format_html_display_cut (EMFormatHTMLDisplay *efhd)
 {
@@ -1302,6 +1297,7 @@
 static gboolean
 efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
 {
+#if 0  /* KILL-BONOBO  !! FIXME !! */
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
 	EAttachment *new;
 	struct _attach_puri *info;
@@ -1324,7 +1320,10 @@
 		return TRUE;
 	}
 
-	if (efhd->priv->attachment_bar) {
+	if (efhd->priv->attachment_view) {
+		EAttachmentView *view;
+		EAttachmentStore *store;
+
 		file = camel_mime_part_get_filename(info->puri.part);
 
 		new = info->attachment;
@@ -1457,6 +1456,7 @@
 		gtk_widget_hide(info->down);
 
 	gtk_container_add((GtkContainer *)eb, mainbox);
+#endif
 
 	return TRUE;
 }
@@ -1500,6 +1500,7 @@
 static void
 attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd)
 {
+#if 0  /* KILL-BONOBO */
 	GSList *attachment_parts;
 	guint n_attachment_parts;
 	gpointer parent;
@@ -1522,31 +1523,10 @@
 			attachment_parts);
 
         g_slist_free (attachment_parts);
+#endif
 }
 
-static void
-efhd_bar_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
-	EAttachmentBar *bar = user_data;
-	GnomeIconList *icon_list = user_data;
-	GList *selection;
-	GnomeCanvasPixbuf *image;
-
-	gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
-
-	selection = gnome_icon_list_get_selection (icon_list);
-	if (selection == NULL)
-		return;
-
-	image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data));
-	if (image == NULL)
-		return;
-
-	/* Put menu to the center of icon. */
-	*x += (int)(image->item.x1 + image->item.x2) / 2;
-	*y += (int)(image->item.y1 + image->item.y2) / 2;
-}
-
+#if 0  /* KILL-BONOBO -- Move this to EAttachmentView */
 static void
 efhd_bar_save_selected(EPopup *ep, EPopupItem *item, void *data)
 {
@@ -1582,68 +1562,24 @@
 	{ E_POPUP_BAR, "05.display", },
 	{ E_POPUP_ITEM, "05.display.01", N_("_Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE},
 };
-
-static gboolean
-efhd_bar_button_press_event(EAttachmentBar *bar, GdkEventButton *event, EMFormat *emf)
-{
-	GtkMenu *menu;
-	GSList *list=NULL;
-	EPopupTarget *target;
-	EMPopup *emp;
-	GSList *menus = NULL;
-	int i;
-
-	if (event && event->button != 3)
-		return FALSE;
-
-	/** @HookPoint-EMPopup: Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.mail.attachments.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: EMPopupTargetPart
-	 *
-	 * This is the drop-down menu shown when a user clicks on the attachment bar
-	 * when attachments are selected.
-	 */
-	emp = em_popup_new("org.gnome.evolution.mail.attachments.popup");
-
-	/* Add something like save-selected, foward selected attachments in a mail etc....*/
-	list = e_attachment_bar_get_selected(bar);
-
-	/* Lets not propagate any more the r-click which is intended to us*/
-	if ( g_slist_length (list) == 0)
-		return TRUE;
-
-	target = (EPopupTarget *)em_popup_target_new_attachments(emp, list);
-	for (i=0; i<2; i++)
-		menus = g_slist_prepend(menus, &efhd_bar_menu_items[i]);
-	e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, emf);
-
-	((EMPopupTargetPart *)target)->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
-	if (event)
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
-	else
-		gtk_menu_popup(menu, NULL, NULL, (GtkMenuPositionFunc)efhd_bar_popup_position, bar, 0, gtk_get_current_event_time());
-
-	return TRUE;
-}
-
-static gboolean
-efhd_bar_popup_menu_event (EAttachmentBar *bar, EMFormat *emf)
-{
-	return efhd_bar_button_press_event(bar, NULL, emf);
-}
+#endif
 
 static void
 efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd)
 {
-	int nattachments;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	guint nattachments;
 
-	if (!efhd->priv->attachment_bar)
+	if (!efhd->priv->attachment_view)
 		return;
 
-	nattachments = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR(efhd->priv->attachment_bar));
-	if (nattachments) {
+	view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
+
+	nattachments = e_attachment_store_get_num_attachments (store);
+
+	if (nattachments > 0) {
 		char *txt;
 
 		/* Cant i put in the number of attachments here ?*/
@@ -1673,6 +1609,7 @@
 static void
 efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh)
 {
+#if 0 /* KILL-BONOBO -- Does EAttachmentIconView need a resize method? */
 	int width;
 	GtkRequisition req;
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
@@ -1683,17 +1620,20 @@
 	/* Update the width of the bar when the width is greater than 1*/
 	if (width > 0)
 		e_attachment_bar_set_width(E_ATTACHMENT_BAR(efhd->priv->attachment_bar), width);
+#endif
 }
 
 static gboolean
 efhd_bar_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd)
 {
+#if 0  /* KILL-BONOBO -- Do we still need this for a GtkIconView? */
 	gboolean ret;
 
 	/* Emulate the scroll over the attachment bar, as if it is scrolled in the window.
 	*  It doesnt go automatically since the GnomeIconList is a layout by itself
 	*/
 	g_signal_emit_by_name (gtk_widget_get_parent((GtkWidget *)efhd->parent.html), "scroll_event", event, &ret);
+#endif
 
 	return TRUE;
 }
@@ -1709,11 +1649,13 @@
 static gboolean
 efhd_update_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
 {
+#if 0  /* KILL-BONOBO -- Does EAttachmentIconView need a refresh method? */
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
 	struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv;
 
 	if (priv->attachment_bar)
 		e_attachment_bar_refresh (E_ATTACHMENT_BAR (priv->attachment_bar));
+#endif
 
 	return TRUE;
 }
@@ -1726,10 +1668,9 @@
 	GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image, *save, *scroll;
 	int width, height, bar_width;
 
-	priv->attachment_bar = e_attachment_bar_new ();
+	priv->attachment_view = e_attachment_icon_view_new ();
 	scroll = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	((EAttachmentBar *)priv->attachment_bar)->expand = TRUE;
 
 	priv->forward = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
 	priv->down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
@@ -1759,14 +1700,14 @@
 
 	priv->attachment_box = scroll;
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
-	gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_bar);
+	gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_view);
 
-	gtk_widget_get_size_request(priv->attachment_bar, &width, &height);
+	gtk_widget_get_size_request(priv->attachment_view, &width, &height);
 
 	/* FIXME: What if the text is more?. Should we reduce the text with appending ...?
 	 * or resize the bar? How to figure out that, it needs more space? */
 	bar_width = ((GtkWidget *)efh->html)->parent->allocation.width - /* FIXME */16;
-	gtk_widget_set_size_request (priv->attachment_bar,
+	gtk_widget_set_size_request (priv->attachment_view,
 				     bar_width > 0 ? bar_width : 0,
 				     84 /* FIXME: Default show only one row, Dont hardcode size*/);
 
@@ -1782,11 +1723,8 @@
 	gtk_widget_hide_all (priv->attachment_area);
 
 	g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh);
-	g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK(efhd_bar_button_press_event), efhd);
-	g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK(efhd_bar_popup_menu_event), efhd);
 	g_signal_connect (save, "clicked", G_CALLBACK(attachments_save_all_clicked), efh);
 	g_signal_connect (eb, "size_allocate", G_CALLBACK (efhd_bar_resize), efh);
-	g_signal_connect (priv->attachment_bar, "scroll_event", G_CALLBACK(efhd_bar_scroll_event), efhd);
 
 	return TRUE;
 }

Modified: branches/kill-bonobo/mail/em-format-html-display.h
==============================================================================
--- branches/kill-bonobo/mail/em-format-html-display.h	(original)
+++ branches/kill-bonobo/mail/em-format-html-display.h	Fri Mar 20 19:06:59 2009
@@ -27,7 +27,6 @@
 
 #include <camel/camel-mime-part.h>
 #include <mail/em-format-html.h>
-#include <widgets/misc/e-attachment-bar.h>
 
 /* Standard GObject macros */
 #define EM_TYPE_FORMAT_HTML_DISPLAY \
@@ -76,7 +75,6 @@
 void		em_format_html_display_zoom_out	(EMFormatHTMLDisplay *efhd);
 void		em_format_html_display_zoom_reset
 						(EMFormatHTMLDisplay *efhd);
-EAttachmentBar *em_format_html_display_get_bar	(EMFormatHTMLDisplay *efhd);
 
 gboolean	em_format_html_display_popup_menu
 						(EMFormatHTMLDisplay *efhd);

Modified: branches/kill-bonobo/mail/em-popup.c
==============================================================================
--- branches/kill-bonobo/mail/em-popup.c	(original)
+++ branches/kill-bonobo/mail/em-popup.c	Fri Mar 20 19:06:59 2009
@@ -117,7 +117,9 @@
 	klass->finalize = emp_finalise;
 	((EPopupClass *)klass)->target_free = emp_target_free;
 
+#if 0  /* KILL-BONOBO */
 	e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL);
+#endif
 }
 
 GType
@@ -361,6 +363,7 @@
 	return t;
 }
 
+#if 0  /* KILL-BONOBO */
 /**
  * em_popup_target_new_attachments:
  * @emp:
@@ -406,9 +409,11 @@
 
 	return t;
 }
+#endif
 
 /* ********************************************************************** */
 
+#if 0  /* KILL-BONOBO */
 static void
 emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
 {
@@ -432,7 +437,9 @@
 
 	em_utils_save_part (parent, _("Save As..."), part);
 }
+#endif
 
+#if 0  /* KILL-BONOBO */
 static void
 emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
 {
@@ -511,6 +518,7 @@
 
 	g_free(path);
 }
+#endif
 
 static void
 emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data)
@@ -589,6 +597,7 @@
 	em_utils_forward_message(message, NULL);
 }
 
+#if 0  /* KILL-BONOBO */
 static EMPopupItem emp_standard_object_popups[] = {
 	{ E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 },
 	{ E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE },
@@ -612,6 +621,7 @@
 };
 
 static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
+#endif
 
 /* ********************************************************************** */
 
@@ -771,6 +781,7 @@
 	camel_object_unref (mem);
 }
 
+#if 0  /* KILL-BONOBO */
 static void
 emp_standard_menu_factory(EPopup *emp, void *data)
 {
@@ -912,6 +923,7 @@
 	if (menus)
 		e_popup_add_items(emp, menus, NULL, emp_standard_items_free, NULL);
 }
+#endif
 
 /* ********************************************************************** */
 

Modified: branches/kill-bonobo/plugins/attachment-reminder/attachment-reminder.c
==============================================================================
--- branches/kill-bonobo/plugins/attachment-reminder/attachment-reminder.c	(original)
+++ branches/kill-bonobo/plugins/attachment-reminder/attachment-reminder.c	Fri Mar 20 19:06:59 2009
@@ -24,6 +24,7 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <glade/glade-xml.h>
 #include <gconf/gconf-client.h>
 
 #include <e-util/e-config.h>
@@ -43,7 +44,6 @@
 
 #include <mail/em-utils.h>
 
-#include "widgets/misc/e-attachment-bar.h"
 #include "composer/e-msg-composer.h"
 #include "composer/e-composer-actions.h"
 
@@ -182,12 +182,13 @@
 static gboolean
 check_for_attachment (EMsgComposer *composer)
 {
-	EAttachmentBar* bar = (EAttachmentBar*)e_msg_composer_get_attachment_bar (composer);
+	EAttachmentView *view;
+	EAttachmentStore *store;
 
-	if (e_attachment_bar_get_num_attachments (bar))
-		return TRUE;
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
-	return FALSE;
+	return (e_attachment_store_get_num_attachments (store) > 0);
 }
 
 static gchar*

Modified: branches/kill-bonobo/plugins/import-ics-attachments/icsimporter.c
==============================================================================
--- branches/kill-bonobo/plugins/import-ics-attachments/icsimporter.c	(original)
+++ branches/kill-bonobo/plugins/import-ics-attachments/icsimporter.c	Fri Mar 20 19:06:59 2009
@@ -36,7 +36,6 @@
 #include <mail/em-folder-view.h>
 #include <mail/em-format-html-display.h>
 #include <mail/em-utils.h>
-#include "e-attachment-bar.h"
 #include <camel/camel-vee-folder.h>
 #include "e-util/e-error.h"
 #include <libedataserverui/e-source-selector.h>

Modified: branches/kill-bonobo/shell/e-shell.c
==============================================================================
--- branches/kill-bonobo/shell/e-shell.c	(original)
+++ branches/kill-bonobo/shell/e-shell.c	Fri Mar 20 19:06:59 2009
@@ -170,12 +170,19 @@
 	if (!is_last_ref)
 		return;
 
+	/* Increment the reference count so we can safely emit
+	 * a signal without triggering the toggle reference. */
+	g_object_ref (activity);
+
 	e_activity_complete (activity);
 
 	g_object_remove_toggle_ref (
 		G_OBJECT (activity), (GToggleNotify)
 		shell_ready_for_offline, shell);
 
+	/* Finalize the activity. */
+	g_object_unref (activity);
+
 	shell->priv->online = FALSE;
 	g_object_notify (G_OBJECT (shell), "online");
 
@@ -217,12 +224,19 @@
 	if (!is_last_ref)
 		return;
 
+	/* Increment the reference count so we can safely emit
+	 * a signal without triggering the toggle reference. */
+	g_object_ref (activity);
+
 	e_activity_complete (activity);
 
 	g_object_remove_toggle_ref (
 		G_OBJECT (activity), (GToggleNotify)
 		shell_ready_for_online, shell);
 
+	/* Finalize the activity. */
+	g_object_unref (activity);
+
 	shell->priv->online = TRUE;
 	g_object_notify (G_OBJECT (shell), "online");
 

Modified: branches/kill-bonobo/shell/main.c
==============================================================================
--- branches/kill-bonobo/shell/main.c	(original)
+++ branches/kill-bonobo/shell/main.c	Fri Mar 20 19:06:59 2009
@@ -618,13 +618,15 @@
 		shell, "window-destroyed",
 		G_CALLBACK (shell_window_destroyed_cb), NULL);
 
-	g_signal_connect (
-		master_client, "save_yourself",
-		G_CALLBACK (master_client_save_yourself_cb), shell);
-
-	g_signal_connect (
-		master_client, "die",
-		G_CALLBACK (master_client_die_cb), shell);
+	if (master_client != NULL) {
+		g_signal_connect (
+			master_client, "save_yourself",
+			G_CALLBACK (master_client_save_yourself_cb), shell);
+
+		g_signal_connect (
+			master_client, "die",
+			G_CALLBACK (master_client_die_cb), shell);
+	}
 
 	g_object_unref (conf_client);
 

Modified: branches/kill-bonobo/widgets/misc/Makefile.am
==============================================================================
--- branches/kill-bonobo/widgets/misc/Makefile.am	(original)
+++ branches/kill-bonobo/widgets/misc/Makefile.am	Fri Mar 20 19:06:59 2009
@@ -40,8 +40,12 @@
 	e-activity-proxy.h			\
 	e-alert-activity.h			\
 	e-attachment.h				\
-	e-attachment-bar.h			\
 	e-attachment-dialog.h			\
+	e-attachment-icon-view.h		\
+	e-attachment-paned.h			\
+	e-attachment-store.h			\
+	e-attachment-tree-view.h		\
+	e-attachment-view.h			\
 	e-calendar.h				\
 	e-calendar-item.h			\
 	e-canvas.h				\
@@ -98,8 +102,12 @@
 	e-activity-proxy.c			\
 	e-alert-activity.c			\
 	e-attachment.c				\
-	e-attachment-bar.c			\
 	e-attachment-dialog.c			\
+	e-attachment-icon-view.c		\
+	e-attachment-paned.c			\
+	e-attachment-store.c			\
+	e-attachment-tree-view.c		\
+	e-attachment-view.c			\
 	e-calendar.c				\
 	e-calendar-item.c			\
 	e-canvas.c				\

Modified: branches/kill-bonobo/widgets/misc/e-activity.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-activity.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-activity.c	Fri Mar 20 19:06:59 2009
@@ -21,6 +21,7 @@
 
 #include "e-activity.h"
 
+#include <stdarg.h>
 #include <glib/gi18n.h>
 
 #define E_ACTIVITY_GET_PRIVATE(obj) \
@@ -32,6 +33,8 @@
 	gchar *primary_text;
 	gchar *secondary_text;
 	gdouble percent;
+	guint idle_id;
+	GError *error;
 
 	guint allow_cancel	: 1;
 	guint blocking		: 1;
@@ -61,6 +64,24 @@
 static gpointer parent_class;
 static gulong signals[LAST_SIGNAL];
 
+static gboolean
+activity_idle_cancel_cb (EActivity *activity)
+{
+	activity->priv->idle_id = 0;
+	e_activity_cancel (activity);
+
+	return FALSE;
+}
+
+static gboolean
+activity_idle_complete_cb (EActivity *activity)
+{
+	activity->priv->idle_id = 0;
+	e_activity_complete (activity);
+
+	return FALSE;
+}
+
 static void
 activity_set_property (GObject *object,
                        guint property_id,
@@ -178,6 +199,12 @@
 	g_free (priv->primary_text);
 	g_free (priv->secondary_text);
 
+	if (priv->idle_id > 0)
+		g_source_remove (priv->idle_id);
+
+	if (priv->error != NULL)
+		g_error_free (priv->error);
+
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -222,12 +249,22 @@
 activity_cancelled (EActivity *activity)
 {
 	activity->priv->cancelled = TRUE;
+
+	if (activity->priv->idle_id > 0) {
+		g_source_remove (activity->priv->idle_id);
+		activity->priv->idle_id = 0;
+	}
 }
 
 static void
 activity_completed (EActivity *activity)
 {
 	activity->priv->completed = TRUE;
+
+	if (activity->priv->idle_id > 0) {
+		g_source_remove (activity->priv->idle_id);
+		activity->priv->idle_id = 0;
+	}
 }
 
 static void
@@ -401,11 +438,29 @@
 		"primary-text", primary_text, NULL);
 }
 
+EActivity *
+e_activity_newv (const gchar *format, ...)
+{
+	EActivity *activity;
+	gchar *primary_text;
+	va_list args;
+
+	va_start (args, format);
+	primary_text = g_strdup_vprintf (format, args);
+	activity = e_activity_new (primary_text);
+	g_free (primary_text);
+	va_end (args);
+
+	return activity;
+}
+
 void
 e_activity_cancel (EActivity *activity)
 {
 	g_return_if_fail (E_IS_ACTIVITY (activity));
-	g_return_if_fail (activity->priv->allow_cancel);
+
+	if (!activity->priv->allow_cancel);
+		return;
 
 	if (activity->priv->cancelled)
 		return;
@@ -417,6 +472,18 @@
 }
 
 void
+e_activity_cancel_in_idle (EActivity *activity)
+{
+	g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	if (activity->priv->idle_id > 0)
+		g_source_remove (activity->priv->idle_id);
+
+	activity->priv->idle_id = g_idle_add (
+		(GSourceFunc) activity_idle_cancel_cb, activity);
+}
+
+void
 e_activity_complete (EActivity *activity)
 {
 	g_return_if_fail (E_IS_ACTIVITY (activity));
@@ -431,6 +498,18 @@
 }
 
 void
+e_activity_complete_in_idle (EActivity *activity)
+{
+	g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	if (activity->priv->idle_id > 0)
+		g_source_remove (activity->priv->idle_id);
+
+	activity->priv->idle_id = g_idle_add (
+		(GSourceFunc) activity_idle_complete_cb, activity);
+}
+
+void
 e_activity_clicked (EActivity *activity)
 {
 	g_return_if_fail (E_IS_ACTIVITY (activity));
@@ -602,3 +681,34 @@
 
 	g_object_notify (G_OBJECT (activity), "secondary-text");
 }
+
+void
+e_activity_set_error (EActivity *activity,
+                      const GError *error)
+{
+	g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	if (activity->priv->error != NULL) {
+		g_error_free (activity->priv->error);
+		activity->priv->error = NULL;
+	}
+
+	if (error != NULL)
+		activity->priv->error = g_error_copy (error);
+}
+
+gboolean
+e_activity_propagate_error (EActivity *activity,
+                            GError **destination)
+{
+	gboolean propagated;
+
+	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+	if ((propagated = (activity->priv->error != NULL))) {
+		g_propagate_error (destination, activity->priv->error);
+		activity->priv->error = NULL;
+	}
+
+	return propagated;
+}

Modified: branches/kill-bonobo/widgets/misc/e-activity.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-activity.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-activity.h	Fri Mar 20 19:06:59 2009
@@ -68,8 +68,12 @@
 
 GType		e_activity_get_type		(void);
 EActivity *	e_activity_new			(const gchar *primary_text);
+EActivity *	e_activity_newv			(const gchar *format,
+						 ...) G_GNUC_PRINTF (1, 2);
 void		e_activity_cancel		(EActivity *activity);
+void		e_activity_cancel_in_idle	(EActivity *activity);
 void		e_activity_complete		(EActivity *activity);
+void		e_activity_complete_in_idle	(EActivity *activity);
 void		e_activity_clicked		(EActivity *activity);
 gchar *		e_activity_describe		(EActivity *activity);
 gboolean	e_activity_is_cancelled		(EActivity *activity);
@@ -95,6 +99,10 @@
 const gchar *	e_activity_get_secondary_text	(EActivity *activity);
 void		e_activity_set_secondary_text	(EActivity *activity,
 						 const gchar *secondary_text);
+void		e_activity_set_error		(EActivity *activity,
+						 const GError *error);
+gboolean	e_activity_propagate_error	(EActivity *activity,
+						 GError **destination);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/widgets/misc/e-attachment-bar.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-bar.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-bar.c	Fri Mar 20 19:06:59 2009
@@ -80,7 +80,6 @@
 struct _EAttachmentBarPrivate {
 	gboolean batch_unref;
 	GPtrArray *attachments;
-	gchar *current_folder;
 	char *path;
 
 	GtkUIManager *ui_manager;
@@ -89,17 +88,11 @@
 	GtkActionGroup *open_actions;
 	guint merge_id;
 
-	gchar *background_filename;
-	gchar *background_options;
-
 	guint editable : 1;
 };
 
 enum {
 	PROP_0,
-	PROP_BACKGROUND_FILENAME,
-	PROP_BACKGROUND_OPTIONS,
-	PROP_CURRENT_FOLDER,
 	PROP_EDITABLE,
 	PROP_UI_MANAGER
 };
@@ -129,78 +122,6 @@
 "</ui>";
 
 static void
-action_add_cb (GtkAction *action,
-               EAttachmentBar *attachment_bar)
-{
-	GtkWidget *dialog;
-	GtkWidget *option;
-	GSList *uris, *iter;
-	const gchar *disposition;
-	gboolean active;
-	gpointer parent;
-	gint response;
-
-	parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar));
-	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
-	dialog = gtk_file_chooser_dialog_new (
-		_("Insert Attachment"), parent,
-		GTK_FILE_CHOOSER_ACTION_OPEN,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		_("A_ttach"), GTK_RESPONSE_OK,
-		NULL);
-
-	gtk_dialog_set_default_response (
-		GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-	gtk_file_chooser_set_local_only (
-		GTK_FILE_CHOOSER (dialog), FALSE);
-	gtk_file_chooser_set_select_multiple (
-		GTK_FILE_CHOOSER (dialog), TRUE);
-	gtk_window_set_icon_name (
-		GTK_WINDOW (dialog), "mail-attachment");
-
-	option = gtk_check_button_new_with_mnemonic (
-		_("_Suggest automatic display of attachment"));
-	gtk_file_chooser_set_extra_widget (
-		GTK_FILE_CHOOSER (dialog), option);
-	gtk_widget_show (option);
-
-	response = e_attachment_bar_file_chooser_dialog_run (
-		attachment_bar, dialog);
-
-	if (response != GTK_RESPONSE_OK)
-		goto exit;
-
-	uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
-	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
-	disposition = active ? "inline" : "attachment";
-
-	for (iter = uris; iter != NULL; iter = iter->next) {
-		CamelURL *url;
-
-		url = camel_url_new (iter->data, NULL);
-		if (url == NULL)
-			continue;
-
-		/* XXX Do we really need two different attach functions? */
-		if (g_ascii_strcasecmp (url->protocol, "file") == 0)
-			e_attachment_bar_attach (
-				attachment_bar, url->path, disposition);
-		else
-			e_attachment_bar_attach_remote_file (
-				attachment_bar, iter->data, disposition);
-
-		camel_url_free (url);
-	}
-
-	g_slist_foreach (uris, (GFunc) g_free, NULL);
-	g_slist_free (uris);
-
-exit:
-	gtk_widget_destroy (dialog);
-}
-
-static void
 action_properties_cb (GtkAction *action,
                       EAttachmentBar *attachment_bar)
 {
@@ -233,33 +154,6 @@
 }
 
 static void
-action_recent_cb (GtkAction *action,
-                  EAttachmentBar *attachment_bar)
-{
-	GtkRecentChooser *chooser;
-	GFile *file;
-	gchar *uri;
-
-	chooser = GTK_RECENT_CHOOSER (action);
-
-	/* Wish: gtk_recent_chooser_get_current_file() */
-	uri = gtk_recent_chooser_get_current_uri (chooser);
-	file = g_file_new_for_uri (uri);
-	g_free (uri);
-
-	if (g_file_is_native (file))
-		e_attachment_bar_attach (
-			E_ATTACHMENT_BAR (attachment_bar),
-			g_file_get_path (file), "attachment");
-	else
-		e_attachment_bar_attach_remote_file (
-			E_ATTACHMENT_BAR (attachment_bar),
-			g_file_get_uri (file), "attachment");
-
-	g_object_unref (file);
-}
-
-static void
 action_remove_cb (GtkAction *action,
                   EAttachmentBar *attachment_bar)
 {
@@ -409,47 +303,6 @@
 	}
 }
 
-static GtkActionEntry standard_entries[] = {
-
-	{ "save-as",
-	  GTK_STOCK_SAVE_AS,
-	  NULL,
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_save_as_cb) },
-
-	{ "set-background",
-	  NULL,
-	  N_("Set as _Background"),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_set_background_cb) }
-};
-
-static GtkActionEntry editable_entries[] = {
-
-	{ "add",
-	  GTK_STOCK_ADD,
-	  N_("A_dd Attachment..."),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_add_cb) },
-
-	{ "properties",
-	  GTK_STOCK_PROPERTIES,
-	  NULL,
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_properties_cb) },
-
-	{ "remove",
-	  GTK_STOCK_REMOVE,
-	  NULL,
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_remove_cb) }
-};
-
 static void
 attachment_bar_show_popup_menu (EAttachmentBar *attachment_bar,
                                 GdkEventButton *event)
@@ -950,24 +803,6 @@
                              GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_BACKGROUND_FILENAME:
-			e_attachment_bar_set_background_filename (
-				E_ATTACHMENT_BAR (object),
-				g_value_get_string (value));
-			return;
-
-		case PROP_BACKGROUND_OPTIONS:
-			e_attachment_bar_set_background_options (
-				E_ATTACHMENT_BAR (object),
-				g_value_get_string (value));
-			return;
-
-		case PROP_CURRENT_FOLDER:
-			e_attachment_bar_set_current_folder (
-				E_ATTACHMENT_BAR (object),
-				g_value_get_string (value));
-			return;
-
 		case PROP_EDITABLE:
 			e_attachment_bar_set_editable (
 				E_ATTACHMENT_BAR (object),
@@ -985,27 +820,6 @@
                              GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_BACKGROUND_FILENAME:
-			g_value_set_string (
-				value,
-				e_attachment_bar_get_background_filename (
-				E_ATTACHMENT_BAR (object)));
-			return;
-
-		case PROP_BACKGROUND_OPTIONS:
-			g_value_set_string (
-				value,
-				e_attachment_bar_get_background_options (
-				E_ATTACHMENT_BAR (object)));
-			return;
-
-		case PROP_CURRENT_FOLDER:
-			g_value_set_string (
-				value,
-				e_attachment_bar_get_current_folder (
-				E_ATTACHMENT_BAR (object)));
-			return;
-
 		case PROP_EDITABLE:
 			g_value_set_boolean (
 				value,
@@ -1077,12 +891,8 @@
 	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
 
 	g_ptr_array_free (priv->attachments, TRUE);
-	g_free (priv->current_folder);
 	g_free (priv->path);
 
-	g_free (priv->background_filename);
-	g_free (priv->background_options);
-
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -1092,25 +902,13 @@
 {
 	EAttachmentBarPrivate *priv;
 	GtkActionGroup *action_group;
-	GConfBridge *bridge;
-	const gchar *prop;
-	const gchar *key;
 
 	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
 	action_group = priv->editable_actions;
-	bridge = gconf_bridge_get ();
 
 	e_mutual_binding_new (
 		G_OBJECT (object), "editable",
 		G_OBJECT (action_group), "visible");
-
-	prop = "background-filename";
-	key = "/desktop/gnome/background/picture_filename";
-	gconf_bridge_bind_property (bridge, key, object, prop);
-
-	prop = "background-options";
-	key = "/desktop/gnome/background/picture_options";
-	gconf_bridge_bind_property (bridge, key, object, prop);
 }
 
 static gboolean
@@ -1428,39 +1226,6 @@
 
 	g_object_class_install_property (
 		object_class,
-		PROP_BACKGROUND_FILENAME,
-		g_param_spec_string (
-			"background-filename",
-			"Background Filename",
-			NULL,
-			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_BACKGROUND_OPTIONS,
-		g_param_spec_string (
-			"background-options",
-			"Background Options",
-			NULL,
-			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_CURRENT_FOLDER,
-		g_param_spec_string (
-			"current-folder",
-			"Current Folder",
-			NULL,
-			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
 		PROP_EDITABLE,
 		g_param_spec_boolean (
 			"editable",
@@ -1503,10 +1268,7 @@
 attachment_bar_init (EAttachmentBar *bar)
 {
 	GnomeIconList *icon_list;
-	GtkUIManager *ui_manager;
-	GtkActionGroup *action_group;
 	gint icon_width, window_height;
-	const gchar *domain = GETTEXT_PACKAGE;
 	GError *error = NULL;
 
 	bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
@@ -1532,38 +1294,6 @@
 	gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
 	gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
 	gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
-	ui_manager = gtk_ui_manager_new ();
-	bar->priv->ui_manager = ui_manager;
-	bar->priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
-
-	action_group = gtk_action_group_new ("standard");
-	gtk_action_group_set_translation_domain (action_group, domain);
-	gtk_action_group_add_actions (
-		action_group, standard_entries,
-		G_N_ELEMENTS (standard_entries), bar);
-	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
-	bar->priv->standard_actions = action_group;
-
-	action_group = gtk_action_group_new ("editable");
-	gtk_action_group_set_translation_domain (action_group, domain);
-	gtk_action_group_add_actions (
-		action_group, editable_entries,
-		G_N_ELEMENTS (editable_entries), bar);
-	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
-	bar->priv->editable_actions = action_group;
-
-	action_group = gtk_action_group_new ("open");
-	gtk_action_group_set_translation_domain (action_group, domain);
-	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
-	bar->priv->open_actions = action_group;
-
-	/* Because we are loading from a hard-coded string, there is
-	 * no chance of I/O errors.  Failure here imples a malformed
-	 * UI definition.  Full stop. */
-	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
-	if (error != NULL)
-		g_error ("%s", error->message);
 }
 
 GType
@@ -2038,69 +1768,6 @@
 	e_attachment_bar_add_attachment (bar, attachment);
 }
 
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
-                                    const gchar *action_name,
-                                    const gchar *action_label)
-{
-	GtkAction *action;
-	GtkRecentChooser *chooser;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	action = gtk_recent_action_new (
-		action_name, action_label, NULL, NULL);
-	gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
-
-	chooser = GTK_RECENT_CHOOSER (action);
-	gtk_recent_chooser_set_show_icons (chooser, TRUE);
-	gtk_recent_chooser_set_show_not_found (chooser, FALSE);
-	gtk_recent_chooser_set_show_private (chooser, FALSE);
-	gtk_recent_chooser_set_show_tips (chooser, TRUE);
-	gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
-
-	g_signal_connect (
-		action, "item-activated",
-		G_CALLBACK (action_recent_cb), bar);
-
-	return action;
-}
-
-gint
-e_attachment_bar_file_chooser_dialog_run (EAttachmentBar *attachment_bar,
-                                          GtkWidget *dialog)
-{
-	GtkFileChooser *file_chooser;
-	gint response = GTK_RESPONSE_NONE;
-	const gchar *current_folder;
-	gboolean save_folder;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), response);
-	g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
-
-	file_chooser = GTK_FILE_CHOOSER (dialog);
-	current_folder = e_attachment_bar_get_current_folder (attachment_bar);
-	gtk_file_chooser_set_current_folder (file_chooser, current_folder);
-
-	response = gtk_dialog_run (GTK_DIALOG (dialog));
-
-	save_folder =
-		(response == GTK_RESPONSE_ACCEPT) ||
-		(response == GTK_RESPONSE_OK) ||
-		(response == GTK_RESPONSE_YES) ||
-		(response == GTK_RESPONSE_APPLY);
-
-	if (save_folder) {
-		gchar *folder;
-
-		folder = gtk_file_chooser_get_current_folder (file_chooser);
-		e_attachment_bar_set_current_folder (attachment_bar, folder);
-		g_free (folder);
-	}
-
-	return response;
-}
-
 void
 e_attachment_bar_update_actions (EAttachmentBar *attachment_bar)
 {
@@ -2109,82 +1776,6 @@
 	g_signal_emit (attachment_bar, signals[UPDATE_ACTIONS], 0);
 }
 
-const gchar *
-e_attachment_bar_get_background_filename (EAttachmentBar *attachment_bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-
-	return attachment_bar->priv->background_filename;
-}
-
-void
-e_attachment_bar_set_background_filename (EAttachmentBar *attachment_bar,
-                                          const gchar *background_filename)
-{
-	EAttachmentBarPrivate *priv;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
-
-	if (background_filename == NULL)
-		background_filename = "";
-
-	priv = attachment_bar->priv;
-	g_free (priv->background_filename);
-	priv->background_filename = g_strdup (background_filename);
-
-	g_object_notify (G_OBJECT (attachment_bar), "background-filename");
-}
-
-const gchar *
-e_attachment_bar_get_background_options (EAttachmentBar *attachment_bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-
-	return attachment_bar->priv->background_options;
-}
-
-void
-e_attachment_bar_set_background_options (EAttachmentBar *attachment_bar,
-                                         const gchar *background_options)
-{
-	EAttachmentBarPrivate *priv;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
-
-	if (background_options == NULL)
-		background_options = "none";
-
-	priv = attachment_bar->priv;
-	g_free (priv->background_options);
-	priv->background_options = g_strdup (background_options);
-
-	g_object_notify (G_OBJECT (attachment_bar), "background-options");
-}
-
-const gchar *
-e_attachment_bar_get_current_folder (EAttachmentBar *attachment_bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-
-	return attachment_bar->priv->current_folder;
-}
-
-void
-e_attachment_bar_set_current_folder (EAttachmentBar *attachment_bar,
-                                     const gchar *current_folder)
-{
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
-
-	if (current_folder == NULL)
-		current_folder = g_get_home_dir ();
-
-	g_free (attachment_bar->priv->current_folder);
-	attachment_bar->priv->current_folder = g_strdup (current_folder);
-
-	g_object_notify (G_OBJECT (attachment_bar), "current-folder");
-}
-
 gboolean
 e_attachment_bar_get_editable (EAttachmentBar *attachment_bar)
 {
@@ -2203,39 +1794,3 @@
 
 	g_object_notify (G_OBJECT (attachment_bar), "editable");
 }
-
-GtkUIManager *
-e_attachment_bar_get_ui_manager (EAttachmentBar *attachment_bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-
-	return attachment_bar->priv->ui_manager;
-}
-
-GtkAction *
-e_attachment_bar_get_action (EAttachmentBar *attachment_bar,
-                             const gchar *action_name)
-{
-	GtkUIManager *ui_manager;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-	g_return_val_if_fail (action_name != NULL, NULL);
-
-	ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
-
-	return e_lookup_action (ui_manager, action_name);
-}
-
-GtkActionGroup *
-e_attachment_bar_get_action_group (EAttachmentBar *attachment_bar,
-                                   const gchar *group_name)
-{
-	GtkUIManager *ui_manager;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-	g_return_val_if_fail (group_name != NULL, NULL);
-
-	ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
-
-	return e_lookup_action_group (ui_manager, group_name);
-}

Modified: branches/kill-bonobo/widgets/misc/e-attachment-dialog.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-dialog.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-dialog.c	Fri Mar 20 19:06:59 2009
@@ -29,9 +29,9 @@
 
 struct _EAttachmentDialogPrivate {
 	EAttachment *attachment;
-	GtkWidget *filename_entry;
+	GtkWidget *display_name_entry;
 	GtkWidget *description_entry;
-	GtkWidget *mime_type_label;
+	GtkWidget *content_type_label;
 	GtkWidget *disposition_checkbox;
 };
 
@@ -46,56 +46,54 @@
 attachment_dialog_update (EAttachmentDialog *dialog)
 {
 	EAttachment *attachment;
-	CamelMimePart *mime_part;
+	GFileInfo *file_info;
 	GtkWidget *widget;
+	const gchar *content_type;
+	const gchar *display_name;
+	const gchar *description;
+	const gchar *disposition;
 	gboolean sensitive;
-	const gchar *text;
 	gboolean active;
 
-	/* XXX This is too complex.  I shouldn't have to use the
-	 *     MIME part at all. */
-
 	attachment = e_attachment_dialog_get_attachment (dialog);
-	if (attachment != NULL)
-		mime_part = e_attachment_get_mime_part (attachment);
-	else
-		mime_part = NULL;
 
-	sensitive = (attachment != NULL);
+	if (E_IS_ATTACHMENT (attachment)) {
+		file_info = e_attachment_get_file_info (attachment);
+		content_type = e_attachment_get_content_type (attachment);
+		display_name = e_attachment_get_display_name (attachment);
+		description = e_attachment_get_description (attachment);
+		disposition = e_attachment_get_disposition (attachment);
+	} else {
+		file_info = NULL;
+		content_type = NULL;
+		display_name = NULL;
+		description = NULL;
+		disposition = NULL;
+	}
+
+	sensitive = G_IS_FILE_INFO (file_info);
+
 	gtk_dialog_set_response_sensitive (
 		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
 
-	text = NULL;
-	if (attachment != NULL)
-		text = e_attachment_get_filename (attachment);
-	text = (text != NULL) ? text : "";
-	widget = dialog->priv->filename_entry;
+	if (display_name == NULL)
+		display_name = "";
+	widget = dialog->priv->display_name_entry;
 	gtk_widget_set_sensitive (widget, sensitive);
-	gtk_entry_set_text (GTK_ENTRY (widget), text);
+	gtk_entry_set_text (GTK_ENTRY (widget), display_name);
 
-	text = NULL;
-	if (attachment != NULL)
-		text = e_attachment_get_description (attachment);
-	text = (text != NULL) ? text : "";
+	if (description == NULL)
+		description = "";
 	widget = dialog->priv->description_entry;
 	gtk_widget_set_sensitive (widget, sensitive);
-	gtk_entry_set_text (GTK_ENTRY (widget), text);
+	gtk_entry_set_text (GTK_ENTRY (widget), description);
 
-	text = NULL;
-	if (attachment != NULL)
-		text = e_attachment_get_mime_type (attachment);
-	text = (text != NULL) ? text : "";
-	widget = dialog->priv->mime_type_label;
-	gtk_label_set_text (GTK_LABEL (widget), text);
-
-	active = FALSE;
-	if (mime_part != NULL) {
-		const gchar *disposition;
-
-		disposition = camel_mime_part_get_disposition (mime_part);
-		active = (g_ascii_strcasecmp (disposition, "inline") == 0);
-	} else if (attachment != NULL)
-		active = e_attachment_is_inline (attachment);
+	if (content_type == NULL)
+		content_type = "";
+	widget = dialog->priv->content_type_label;
+	gtk_label_set_text (GTK_LABEL (widget), content_type);
+
+	active = (g_strcmp0 (disposition, "inline") == 0);
 	widget = dialog->priv->disposition_checkbox;
 	gtk_widget_set_sensitive (widget, sensitive);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
@@ -147,9 +145,9 @@
 		priv->attachment = NULL;
 	}
 
-	if (priv->filename_entry != NULL) {
-		g_object_unref (priv->filename_entry);
-		priv->filename_entry = NULL;
+	if (priv->display_name_entry != NULL) {
+		g_object_unref (priv->display_name_entry);
+		priv->display_name_entry = NULL;
 	}
 
 	if (priv->description_entry != NULL) {
@@ -157,9 +155,9 @@
 		priv->description_entry = NULL;
 	}
 
-	if (priv->mime_type_label != NULL) {
-		g_object_unref (priv->mime_type_label);
-		priv->mime_type_label = NULL;
+	if (priv->content_type_label != NULL) {
+		g_object_unref (priv->content_type_label);
+		priv->content_type_label = NULL;
 	}
 
 	if (priv->disposition_checkbox != NULL) {
@@ -196,7 +194,8 @@
 	EAttachmentDialogPrivate *priv;
 	EAttachment *attachment;
 	GtkToggleButton *button;
-	GtkEntry *entry;
+	GFileInfo *file_info;
+	const gchar *attribute;
 	const gchar *text;
 	gboolean active;
 
@@ -204,16 +203,19 @@
 		return;
 
 	priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
-	g_return_if_fail (priv->attachment != NULL);
+	g_return_if_fail (E_IS_ATTACHMENT (priv->attachment));
 	attachment = priv->attachment;
 
-	entry = GTK_ENTRY (priv->filename_entry);
-	text = gtk_entry_get_text (entry);
-	e_attachment_set_filename (attachment, text);
-
-	entry = GTK_ENTRY (priv->description_entry);
-	text = gtk_entry_get_text (entry);
-	e_attachment_set_description (attachment, text);
+	file_info = e_attachment_get_file_info (attachment);
+	g_return_if_fail (G_IS_FILE_INFO (file_info));
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+	text = gtk_entry_get_text (GTK_ENTRY (priv->display_name_entry));
+	g_file_info_set_attribute_string (file_info, attribute, text);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	text = gtk_entry_get_text (GTK_ENTRY (priv->description_entry));
+	g_file_info_set_attribute_string (file_info, attribute, text);
 
 	button = GTK_TOGGLE_BUTTON (priv->disposition_checkbox);
 	active = gtk_toggle_button_get_active (button);
@@ -289,13 +291,13 @@
 	gtk_table_attach (
 		GTK_TABLE (container), widget,
 		1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	dialog->priv->filename_entry = g_object_ref (widget);
+	dialog->priv->display_name_entry = g_object_ref (widget);
 	gtk_widget_show (widget);
 
 	widget = gtk_label_new_with_mnemonic (_("_Filename:"));
 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
 	gtk_label_set_mnemonic_widget (
-		GTK_LABEL (widget), dialog->priv->filename_entry);
+		GTK_LABEL (widget), dialog->priv->display_name_entry);
 	gtk_table_attach (
 		GTK_TABLE (container), widget,
 		0, 1, 0, 1, GTK_FILL, 0, 0, 0);
@@ -324,7 +326,7 @@
 	gtk_table_attach (
 		GTK_TABLE (container), widget,
 		1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	dialog->priv->mime_type_label = g_object_ref (widget);
+	dialog->priv->content_type_label = g_object_ref (widget);
 	gtk_widget_show (widget);
 
 	widget = gtk_label_new (_("MIME Type:"));

Added: branches/kill-bonobo/widgets/misc/e-attachment-icon-view.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-icon-view.c	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,319 @@
+/*
+ * e-attachment-icon-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-icon-view.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "e-attachment.h"
+#include "e-attachment-store.h"
+#include "e-attachment-view.h"
+
+#define E_ATTACHMENT_ICON_VIEW_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconViewPrivate))
+
+struct _EAttachmentIconViewPrivate {
+	EAttachmentViewPrivate view_priv;
+};
+
+static gpointer parent_class;
+
+static void
+attachment_icon_view_dispose (GObject *object)
+{
+	e_attachment_view_dispose (E_ATTACHMENT_VIEW (object));
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_icon_view_finalize (GObject *object)
+{
+	e_attachment_view_finalize (E_ATTACHMENT_VIEW (object));
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+attachment_icon_view_button_press_event (GtkWidget *widget,
+                                         GdkEventButton *event)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+		e_attachment_view_show_popup_menu (view, event);
+		return TRUE;
+	}
+
+	/* Chain up to parent's button_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		button_press_event (widget, event);
+}
+
+static gboolean
+attachment_icon_view_key_press_event (GtkWidget *widget,
+                                      GdkEventKey *event)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	if (event->keyval == GDK_Delete) {
+		e_attachment_view_remove_selected (view, TRUE);
+		return TRUE;
+	}
+
+	/* Chain up to parent's key_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		key_press_event (widget, event);
+}
+
+static gboolean
+attachment_icon_view_drag_motion (GtkWidget *widget,
+                                  GdkDragContext *context,
+                                  gint x,
+                                  gint y,
+                                  guint time)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+attachment_icon_view_drag_data_received (GtkWidget *widget,
+                                         GdkDragContext *context,
+                                         gint x,
+                                         gint y,
+                                         GtkSelectionData *selection,
+                                         guint info,
+                                         guint time)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	e_attachment_view_drag_data_received (
+		view, context, x, y, selection, info, time);
+}
+
+static gboolean
+attachment_icon_view_popup_menu (GtkWidget *widget)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	e_attachment_view_show_popup_menu (view, NULL);
+
+	return TRUE;
+}
+
+static EAttachmentViewPrivate *
+attachment_icon_view_get_private (EAttachmentView *view)
+{
+	EAttachmentIconViewPrivate *priv;
+
+	priv = E_ATTACHMENT_ICON_VIEW_GET_PRIVATE (view);
+
+	return &priv->view_priv;
+}
+
+static EAttachmentStore *
+attachment_icon_view_get_store (EAttachmentView *view)
+{
+	GtkIconView *icon_view;
+	GtkTreeModel *model;
+
+	icon_view = GTK_ICON_VIEW (view);
+	model = gtk_icon_view_get_model (icon_view);
+
+	return E_ATTACHMENT_STORE (model);
+}
+
+static GtkTreePath *
+attachment_icon_view_get_path_at_pos (EAttachmentView *view,
+                                      gint x,
+                                      gint y)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	return gtk_icon_view_get_path_at_pos (icon_view, x, y);
+}
+
+static GList *
+attachment_icon_view_get_selected_paths (EAttachmentView *view)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	return gtk_icon_view_get_selected_items (icon_view);
+}
+
+static gboolean
+attachment_icon_view_path_is_selected (EAttachmentView *view,
+                                       GtkTreePath *path)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	return gtk_icon_view_path_is_selected (icon_view, path);
+}
+
+static void
+attachment_icon_view_select_path (EAttachmentView *view,
+                                  GtkTreePath *path)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	gtk_icon_view_select_path (icon_view, path);
+}
+
+static void
+attachment_icon_view_unselect_path (EAttachmentView *view,
+                                    GtkTreePath *path)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	gtk_icon_view_unselect_path (icon_view, path);
+}
+
+static void
+attachment_icon_view_select_all (EAttachmentView *view)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	gtk_icon_view_select_all (icon_view);
+}
+
+static void
+attachment_icon_view_unselect_all (EAttachmentView *view)
+{
+	GtkIconView *icon_view;
+
+	icon_view = GTK_ICON_VIEW (view);
+
+	gtk_icon_view_unselect_all (icon_view);
+}
+
+static void
+attachment_icon_view_class_init (EAttachmentIconViewClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentViewPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->dispose = attachment_icon_view_dispose;
+	object_class->finalize = attachment_icon_view_finalize;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->button_press_event = attachment_icon_view_button_press_event;
+	widget_class->key_press_event = attachment_icon_view_key_press_event;
+	widget_class->drag_motion = attachment_icon_view_drag_motion;
+	widget_class->drag_data_received = attachment_icon_view_drag_data_received;
+	widget_class->popup_menu = attachment_icon_view_popup_menu;
+}
+
+static void
+attachment_icon_view_iface_init (EAttachmentViewIface *iface)
+{
+	iface->get_private = attachment_icon_view_get_private;
+	iface->get_store = attachment_icon_view_get_store;
+
+	iface->get_path_at_pos = attachment_icon_view_get_path_at_pos;
+	iface->get_selected_paths = attachment_icon_view_get_selected_paths;
+	iface->path_is_selected = attachment_icon_view_path_is_selected;
+	iface->select_path = attachment_icon_view_select_path;
+	iface->unselect_path = attachment_icon_view_unselect_path;
+	iface->select_all = attachment_icon_view_select_all;
+	iface->unselect_all = attachment_icon_view_unselect_all;
+}
+
+static void
+attachment_icon_view_init (EAttachmentIconView *icon_view)
+{
+	icon_view->priv = E_ATTACHMENT_ICON_VIEW_GET_PRIVATE (icon_view);
+
+	e_attachment_view_init (E_ATTACHMENT_VIEW (icon_view));
+
+	gtk_icon_view_set_selection_mode (
+		GTK_ICON_VIEW (icon_view), GTK_SELECTION_MULTIPLE);
+
+	gtk_icon_view_set_pixbuf_column (
+		GTK_ICON_VIEW (icon_view),
+		E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF);
+
+	gtk_icon_view_set_text_column (
+		GTK_ICON_VIEW (icon_view),
+		E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION);
+}
+
+GType
+e_attachment_icon_view_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentIconViewClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_icon_view_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EAttachmentIconView),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_icon_view_init,
+			NULL   /* value_table */
+		};
+
+		static const GInterfaceInfo iface_info = {
+			(GInterfaceInitFunc) attachment_icon_view_iface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_ICON_VIEW, "EAttachmentIconView",
+			&type_info, 0);
+
+		g_type_add_interface_static (
+			type, E_TYPE_ATTACHMENT_VIEW, &iface_info);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_attachment_icon_view_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT_ICON_VIEW, NULL);
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-icon-view.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-icon-view.h	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,66 @@
+/*
+ * e-attachment-icon-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_ICON_VIEW_H
+#define E_ATTACHMENT_ICON_VIEW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_ICON_VIEW \
+	(e_attachment_icon_view_get_type ())
+#define E_ATTACHMENT_ICON_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconView))
+#define E_ATTACHMENT_ICON_VIEW_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconView))
+#define E_IS_ATTACHMENT_ICON_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_ICON_VIEW))
+#define E_IS_ATTACHMENT_ICON_VIEW_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_ICON_VIEW))
+#define E_ATTACHMENT_ICON_VIEW_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_ICON_VIEW))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentIconView EAttachmentIconView;
+typedef struct _EAttachmentIconViewClass EAttachmentIconViewClass;
+typedef struct _EAttachmentIconViewPrivate EAttachmentIconViewPrivate;
+
+struct _EAttachmentIconView {
+	GtkIconView parent;
+	EAttachmentIconViewPrivate *priv;
+};
+
+struct _EAttachmentIconViewClass {
+	GtkIconViewClass parent_class;
+};
+
+GType		e_attachment_icon_view_get_type		(void);
+GtkWidget *	e_attachment_icon_view_new		(void);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_ICON_VIEW_H */

Added: branches/kill-bonobo/widgets/misc/e-attachment-paned.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-paned.c	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,563 @@
+/*
+ * e-attachment-paned.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-paned.h"
+
+#include <glib/gi18n.h>
+#include "e-util/e-binding.h"
+#include "e-attachment-store.h"
+#include "e-attachment-icon-view.h"
+#include "e-attachment-tree-view.h"
+
+#define E_ATTACHMENT_PANED_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedPrivate))
+
+#define NUM_VIEWS 2
+
+struct _EAttachmentPanedPrivate {
+	GtkTreeModel *model;
+	GtkWidget *expander;
+	GtkWidget *notebook;
+	GtkWidget *combo_box;
+	GtkWidget *icon_view;
+	GtkWidget *tree_view;
+	GtkWidget *show_hide_label;
+	GtkWidget *status_icon;
+	GtkWidget *status_label;
+	GtkWidget *content_area;
+
+	gint active_view;
+	guint expanded : 1;
+};
+
+enum {
+	PROP_0,
+	PROP_ACTIVE_VIEW,
+	PROP_EXPANDED
+};
+
+static gpointer parent_class;
+
+static void
+attachment_paned_notify_cb (EAttachmentPaned *paned,
+                            GParamSpec *pspec,
+                            GtkExpander *expander)
+{
+	GtkLabel *label;
+	const gchar *text;
+
+	label = GTK_LABEL (paned->priv->show_hide_label);
+
+	/* Update the expander label. */
+	if (gtk_expander_get_expanded (expander))
+		text = _("Hide _Attachment Bar");
+	else
+		text = _("Show _Attachment Bar");
+
+	gtk_label_set_text_with_mnemonic (label, text);
+}
+
+static void
+attachment_paned_sync_icon_view (EAttachmentPaned *paned)
+{
+	EAttachmentView *source;
+	EAttachmentView *target;
+
+	source = E_ATTACHMENT_VIEW (paned->priv->tree_view);
+	target = E_ATTACHMENT_VIEW (paned->priv->icon_view);
+
+	/* Only sync if the tree view is active.  This prevents the
+	 * two views from endlessly trying to sync with each other. */
+	if (e_attachment_paned_get_active_view (paned) == 1)
+		e_attachment_view_sync_selection (source, target);
+}
+
+static void
+attachment_paned_sync_tree_view (EAttachmentPaned *paned)
+{
+	EAttachmentView *source;
+	EAttachmentView *target;
+
+	source = E_ATTACHMENT_VIEW (paned->priv->icon_view);
+	target = E_ATTACHMENT_VIEW (paned->priv->tree_view);
+
+	/* Only sync if the icon view is active.  This prevents the
+	 * two views from endlessly trying to sync with each other. */
+	if (e_attachment_paned_get_active_view (paned) == 0)
+		e_attachment_view_sync_selection (source, target);
+}
+
+static void
+attachment_paned_update_status (EAttachmentPaned *paned)
+{
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	GtkExpander *expander;
+	GtkLabel *label;
+	guint num_attachments;
+	guint64 total_size;
+	gchar *display_size;
+	gchar *markup;
+
+	view = e_attachment_paned_get_view (paned);
+	store = e_attachment_view_get_store (view);
+	expander = GTK_EXPANDER (paned->priv->expander);
+	label = GTK_LABEL (paned->priv->status_label);
+
+	num_attachments = e_attachment_store_get_num_attachments (store);
+	total_size = e_attachment_store_get_total_size (store);
+	display_size = g_format_size_for_display (total_size);
+
+	markup = g_strdup_printf (
+		"<b>%d</b> %s (%s)", num_attachments, ngettext (
+		"Attachment", "Attachments", num_attachments),
+		display_size);
+	gtk_label_set_markup (label, markup);
+	g_free (markup);
+
+	g_free (display_size);
+
+	if (num_attachments > 0) {
+		gtk_widget_show (paned->priv->status_icon);
+		gtk_widget_show (paned->priv->status_label);
+		gtk_expander_set_expanded (expander, TRUE);
+	} else {
+		gtk_widget_hide (paned->priv->status_icon);
+		gtk_widget_hide (paned->priv->status_label);
+		gtk_expander_set_expanded (expander, FALSE);
+	}
+}
+
+static void
+attachment_paned_set_property (GObject *object,
+                                  guint property_id,
+                                  const GValue *value,
+                                  GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ACTIVE_VIEW:
+			e_attachment_paned_set_active_view (
+				E_ATTACHMENT_PANED (object),
+				g_value_get_int (value));
+			return;
+
+		case PROP_EXPANDED:
+			e_attachment_paned_set_expanded (
+				E_ATTACHMENT_PANED (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_paned_get_property (GObject *object,
+                                  guint property_id,
+                                  GValue *value,
+                                  GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ACTIVE_VIEW:
+			g_value_set_int (
+				value, e_attachment_paned_get_active_view (
+				E_ATTACHMENT_PANED (object)));
+			return;
+
+		case PROP_EXPANDED:
+			g_value_set_boolean (
+				value, e_attachment_paned_get_expanded (
+				E_ATTACHMENT_PANED (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_paned_dispose (GObject *object)
+{
+	EAttachmentPanedPrivate *priv;
+
+	priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
+
+	if (priv->model != NULL) {
+		g_object_unref (priv->model);
+		priv->model = NULL;
+	}
+
+	if (priv->expander != NULL) {
+		g_object_unref (priv->expander);
+		priv->expander = NULL;
+	}
+
+	if (priv->notebook != NULL) {
+		g_object_unref (priv->notebook);
+		priv->notebook = NULL;
+	}
+
+	if (priv->combo_box != NULL) {
+		g_object_unref (priv->combo_box);
+		priv->combo_box = NULL;
+	}
+
+	if (priv->icon_view != NULL) {
+		g_object_unref (priv->icon_view);
+		priv->icon_view = NULL;
+	}
+
+	if (priv->tree_view != NULL) {
+		g_object_unref (priv->tree_view);
+		priv->tree_view = NULL;
+	}
+
+	if (priv->show_hide_label != NULL) {
+		g_object_unref (priv->show_hide_label);
+		priv->show_hide_label = NULL;
+	}
+
+	if (priv->status_icon != NULL) {
+		g_object_unref (priv->status_icon);
+		priv->status_icon = NULL;
+	}
+
+	if (priv->status_label != NULL) {
+		g_object_unref (priv->status_label);
+		priv->status_label = NULL;
+	}
+
+	if (priv->content_area != NULL) {
+		g_object_unref (priv->content_area);
+		priv->content_area = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_paned_constructed (GObject *object)
+{
+	EAttachmentPanedPrivate *priv;
+
+	priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
+
+	e_mutual_binding_new (
+		G_OBJECT (object), "active-view",
+		G_OBJECT (priv->combo_box), "active");
+
+	e_mutual_binding_new (
+		G_OBJECT (object), "active-view",
+		G_OBJECT (priv->notebook), "page");
+
+	e_mutual_binding_new (
+		G_OBJECT (object), "expanded",
+		G_OBJECT (priv->expander), "expanded");
+
+	e_mutual_binding_new (
+		G_OBJECT (object), "expanded",
+		G_OBJECT (priv->combo_box), "sensitive");
+
+	e_mutual_binding_new (
+		G_OBJECT (object), "expanded",
+		G_OBJECT (priv->notebook), "visible");
+}
+
+static void
+attachment_paned_class_init (EAttachmentPanedClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentPanedPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_paned_set_property;
+	object_class->get_property = attachment_paned_get_property;
+	object_class->dispose = attachment_paned_dispose;
+	object_class->constructed = attachment_paned_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ACTIVE_VIEW,
+		g_param_spec_int (
+			"active-view",
+			"Active View",
+			NULL,
+			0,
+			NUM_VIEWS,
+			0,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_EXPANDED,
+		g_param_spec_boolean (
+			"expanded",
+			"Expanded",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_paned_init (EAttachmentPaned *paned)
+{
+	GtkTreeSelection *selection;
+	GtkSizeGroup *size_group;
+	GtkWidget *container;
+	GtkWidget *widget;
+
+	paned->priv = E_ATTACHMENT_PANED_GET_PRIVATE (paned);
+	paned->priv->model = e_attachment_store_new ();
+
+	/* Keep the expander label and combo box the same height. */
+	size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+
+	/* Construct the Controls */
+
+	container = GTK_WIDGET (paned);
+
+	widget = gtk_vbox_new (FALSE, 6);
+	gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+	paned->priv->content_area = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_hbox_new (FALSE, 6);
+	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_expander_new (NULL);
+	gtk_expander_set_spacing (GTK_EXPANDER (widget), 0);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	paned->priv->expander = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_combo_box_new_text ();
+	gtk_size_group_add_widget (size_group, widget);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Icon View"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("List View"));
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	paned->priv->combo_box = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = paned->priv->expander;
+
+	widget = gtk_hbox_new (FALSE, 0);
+	gtk_size_group_add_widget (size_group, widget);
+	gtk_expander_set_label_widget (GTK_EXPANDER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar"));
+	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6);
+	paned->priv->show_hide_label = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_image_new_from_icon_name (
+		"mail-attachment", GTK_ICON_SIZE_MENU);
+	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+	gtk_widget_set_size_request (widget, 100, -1);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	paned->priv->status_icon = g_object_ref (widget);
+	gtk_widget_hide (widget);
+
+	widget = gtk_label_new (NULL);
+	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
+	paned->priv->status_label = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Construct the Attachment Views */
+
+	container = GTK_WIDGET (paned);
+
+	widget = gtk_notebook_new ();
+	gtk_widget_set_size_request (widget, -1, 40);
+	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+	gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, FALSE);
+	paned->priv->notebook = g_object_ref (widget);
+	gtk_widget_hide (widget);
+
+	container = paned->priv->notebook;
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = e_attachment_icon_view_new ();
+	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+	gtk_icon_view_set_model (GTK_ICON_VIEW (widget), paned->priv->model);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	paned->priv->icon_view = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = paned->priv->notebook;
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = e_attachment_tree_view_new ();
+	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget), paned->priv->model);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	paned->priv->tree_view = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	selection = gtk_tree_view_get_selection (
+		GTK_TREE_VIEW (paned->priv->tree_view));
+
+	g_signal_connect_swapped (
+		selection, "changed",
+		G_CALLBACK (attachment_paned_sync_icon_view), paned);
+
+	g_signal_connect_swapped (
+		paned->priv->icon_view, "selection-changed",
+		G_CALLBACK (attachment_paned_sync_tree_view), paned);
+
+	g_signal_connect_swapped (
+		paned->priv->expander, "notify::expanded",
+		G_CALLBACK (attachment_paned_notify_cb), paned);
+
+	g_signal_connect_swapped (
+		paned->priv->model, "notify::num-attachments",
+		G_CALLBACK (attachment_paned_update_status), paned);
+
+	g_signal_connect_swapped (
+		paned->priv->model, "notify::total-size",
+		G_CALLBACK (attachment_paned_update_status), paned);
+
+	g_object_unref (size_group);
+}
+
+GType
+e_attachment_paned_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentPanedClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_paned_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EAttachmentPaned),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_paned_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_VPANED, "EAttachmentPaned",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_attachment_paned_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT_PANED, NULL);
+}
+
+EAttachmentView *
+e_attachment_paned_get_view (EAttachmentPaned *paned)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL);
+
+	return E_ATTACHMENT_VIEW (paned->priv->icon_view);
+}
+
+GtkWidget *
+e_attachment_paned_get_content_area (EAttachmentPaned *paned)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL);
+
+	return paned->priv->content_area;
+}
+
+gint
+e_attachment_paned_get_active_view (EAttachmentPaned *paned)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), 0);
+
+	return paned->priv->active_view;
+}
+
+void
+e_attachment_paned_set_active_view (EAttachmentPaned *paned,
+                                    gint active_view)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
+	g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS);
+
+	paned->priv->active_view = active_view;
+
+	g_object_notify (G_OBJECT (paned), "active-view");
+}
+
+gboolean
+e_attachment_paned_get_expanded (EAttachmentPaned *paned)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), FALSE);
+
+	return paned->priv->expanded;
+}
+
+void
+e_attachment_paned_set_expanded (EAttachmentPaned *paned,
+                                 gboolean expanded)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
+
+	paned->priv->expanded = expanded;
+
+	g_object_notify (G_OBJECT (paned), "expanded");
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-paned.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-paned.h	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,79 @@
+/*
+ * e-attachment-paned.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_PANED_H
+#define E_ATTACHMENT_PANED_H
+
+#include <gtk/gtk.h>
+#include <e-attachment-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_PANED \
+	(e_attachment_paned_get_type ())
+#define E_ATTACHMENT_PANED(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPaned))
+#define E_ATTACHMENT_PANED_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedClass))
+#define E_IS_ATTACHMENT_PANED(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_PANED))
+#define E_IS_ATTACHMENT_PANED_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_PANED))
+#define E_ATTACHMENT_PANED_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentPaned EAttachmentPaned;
+typedef struct _EAttachmentPanedClass EAttachmentPanedClass;
+typedef struct _EAttachmentPanedPrivate EAttachmentPanedPrivate;
+
+struct _EAttachmentPaned {
+	GtkVPaned parent;
+	EAttachmentPanedPrivate *priv;
+};
+
+struct _EAttachmentPanedClass {
+	GtkVPanedClass parent_class;
+};
+
+GType		e_attachment_paned_get_type	(void);
+GtkWidget *	e_attachment_paned_new		(void);
+EAttachmentView *
+		e_attachment_paned_get_view	(EAttachmentPaned *paned);
+GtkWidget *	e_attachment_paned_get_content_area
+						(EAttachmentPaned *paned);
+gint		e_attachment_paned_get_active_view
+						(EAttachmentPaned *paned);
+void		e_attachment_paned_set_active_view
+						(EAttachmentPaned *paned,
+						 gint active_view);
+gboolean	e_attachment_paned_get_expanded	(EAttachmentPaned *paned);
+void		e_attachment_paned_set_expanded	(EAttachmentPaned *paned,
+						 gboolean expanded);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_PANED_H */

Added: branches/kill-bonobo/widgets/misc/e-attachment-store.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-store.c	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,1073 @@
+/*
+ * e-attachment-store.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-store.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
+
+#include "e-file-activity.h"
+
+#define E_ATTACHMENT_STORE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStorePrivate))
+
+#define DEFAULT_ICON_NAME	"mail-attachment"
+
+/* XXX Unfortunate that we have to define this here.  Would
+ *     prefer the attachment view classes pick their own size,
+ *     but GtkIconView requires a dedicated pixbuf column. */
+#define LARGE_ICON_SIZE		GTK_ICON_SIZE_DIALOG
+#define SMALL_ICON_SIZE		GTK_ICON_SIZE_MENU
+
+struct _EAttachmentStorePrivate {
+	GHashTable *activity_index;
+	GHashTable *attachment_index;
+	gchar *background_filename;
+	gchar *background_options;
+	gchar *current_folder;
+
+	guint ignore_row_changed : 1;
+};
+
+enum {
+	PROP_0,
+	PROP_BACKGROUND_FILENAME,
+	PROP_BACKGROUND_OPTIONS,
+	PROP_CURRENT_FOLDER,
+	PROP_NUM_ATTACHMENTS,
+	PROP_NUM_DOWNLOADING,
+	PROP_TOTAL_SIZE
+};
+
+enum {
+	NEW_ACTIVITY,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static const gchar *
+attachment_store_get_background_filename (EAttachmentStore *store)
+{
+	return store->priv->background_filename;
+}
+
+static void
+attachment_store_set_background_filename (EAttachmentStore *store,
+                                          const gchar *background_filename)
+{
+	if (background_filename == NULL)
+		background_filename = "";
+
+	g_free (store->priv->background_filename);
+	store->priv->background_filename = g_strdup (background_filename);
+
+	g_object_notify (G_OBJECT (store), "background-filename");
+}
+
+static const gchar *
+attachment_store_get_background_options (EAttachmentStore *store)
+{
+	return store->priv->background_options;
+}
+
+static void
+attachment_store_set_background_options (EAttachmentStore *store,
+                                         const gchar *background_options)
+{
+	if (background_options == NULL)
+		background_options = "";
+
+	g_free (store->priv->background_options);
+	store->priv->background_options = g_strdup (background_options);
+
+	g_object_notify (G_OBJECT (store), "background-options");
+}
+
+static void
+attachment_store_remove_activity (EAttachmentStore *store,
+                                  EActivity *activity)
+{
+	GtkTreeRowReference *reference;
+	GHashTable *hash_table;
+
+	hash_table = store->priv->activity_index;
+	reference = g_hash_table_lookup (hash_table, activity);
+
+	if (gtk_tree_row_reference_valid (reference)) {
+		GtkTreeModel *model;
+		GtkTreePath *path;
+		GtkTreeIter iter;
+
+		model = gtk_tree_row_reference_get_model (reference);
+		path = gtk_tree_row_reference_get_path (reference);
+		gtk_tree_model_get_iter (model, &iter, path);
+		gtk_tree_path_free (path);
+
+		gtk_list_store_set (
+			GTK_LIST_STORE (store), &iter,
+			E_ATTACHMENT_STORE_COLUMN_ACTIVITY, NULL, -1);
+	}
+
+	g_hash_table_remove (hash_table, activity);
+
+	g_object_notify (G_OBJECT (store), "num-downloading");
+}
+
+static void
+attachment_store_copy_ready (GFile *source,
+                             GAsyncResult *result,
+                             GtkTreeRowReference *reference)
+{
+	EAttachmentStore *store;
+	EAttachment *attachment;
+	EActivity *activity;
+	GFile *destination;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gboolean valid;
+	GError *error = NULL;
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	valid = gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	g_return_if_fail (valid);
+
+	gtk_tree_model_get (
+		model, &iter,
+		E_ATTACHMENT_STORE_COLUMN_ACTIVITY, &activity,
+		E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, &attachment, -1);
+
+	gtk_tree_row_reference_free (reference);
+
+	store = E_ATTACHMENT_STORE (model);
+
+	if (!g_file_copy_finish (source, result, &error))
+		goto fail;
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (store), &iter,
+		E_ATTACHMENT_STORE_COLUMN_ACTIVITY, NULL, -1);
+
+	destination = e_file_activity_get_file (E_FILE_ACTIVITY (activity));
+	e_attachment_set_file (attachment, destination);
+
+	e_activity_complete (activity);
+
+	path = gtk_tree_model_get_path (model, &iter);
+	gtk_tree_model_row_changed (model, path, &iter);
+	gtk_tree_path_free (path);
+
+	g_object_unref (attachment);
+	g_object_unref (activity);
+
+	return;
+
+fail:
+	e_attachment_store_remove_attachment (store, attachment);
+
+	g_object_unref (attachment);
+	g_object_unref (activity);
+
+	/* XXX Do something more useful with the error. */
+	g_warning ("%s", error->message);
+	g_error_free (error);
+}
+
+static void
+attachment_store_copy_async (EAttachmentStore *store,
+                             EAttachment *attachment)
+{
+	EActivity *activity;
+	GCancellable *cancellable;
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	GHashTable *hash_table;
+	GFile *destination;
+	GFile *source;
+	gboolean valid;
+	gchar *filename;
+	gchar *uri;
+	gint fd;
+	GError *error = NULL;
+
+	hash_table = store->priv->attachment_index;
+	reference = g_hash_table_lookup (hash_table, attachment);
+	g_return_if_fail (reference != NULL);
+
+	fd = e_file_open_tmp (&filename, &error);
+	if (error != NULL)
+		goto fail;
+
+	source = e_attachment_get_file (attachment);
+	destination = g_file_new_for_path (filename);
+
+	g_free (filename);
+	close (fd);
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	valid = gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	g_return_if_fail (valid);
+
+	uri = g_file_get_uri (source);
+	activity = e_file_activity_newv (_("Downloading '%s'"), uri);
+	g_free (uri);
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (store), &iter,
+		E_ATTACHMENT_STORE_COLUMN_ACTIVITY, activity, -1);
+
+	reference = gtk_tree_row_reference_copy (reference);
+
+	g_hash_table_insert (hash_table, g_object_ref (activity), reference);
+
+	g_signal_connect_swapped (
+		activity, "cancelled",
+		G_CALLBACK (attachment_store_remove_activity), store);
+
+	g_signal_connect_swapped (
+		activity, "completed",
+		G_CALLBACK (attachment_store_remove_activity), store);
+
+	reference = gtk_tree_row_reference_copy (reference);
+
+	cancellable = e_file_activity_get_cancellable (
+		E_FILE_ACTIVITY (activity));
+
+	g_file_copy_async (
+		source, destination, G_FILE_COPY_OVERWRITE,
+		G_PRIORITY_DEFAULT, cancellable, (GFileProgressCallback)
+		e_file_activity_progress, activity, (GAsyncReadyCallback)
+		attachment_store_copy_ready, reference);
+
+	e_file_activity_set_file (E_FILE_ACTIVITY (activity), destination);
+	g_signal_emit (store, signals[NEW_ACTIVITY], 0, activity);
+
+	g_object_notify (G_OBJECT (store), "num-downloading");
+
+	g_object_unref (activity);
+	g_object_unref (destination);
+
+	return;
+
+fail:
+	e_attachment_store_remove_attachment (store, attachment);
+
+	/* XXX Do something more useful with the error. */
+	g_warning ("%s", error->message);
+	g_error_free (error);
+}
+
+static void
+attachment_store_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BACKGROUND_FILENAME:
+			attachment_store_set_background_filename (
+				E_ATTACHMENT_STORE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_BACKGROUND_OPTIONS:
+			attachment_store_set_background_options (
+				E_ATTACHMENT_STORE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_CURRENT_FOLDER:
+			e_attachment_store_set_current_folder (
+				E_ATTACHMENT_STORE (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_store_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BACKGROUND_FILENAME:
+			g_value_set_string (
+				value,
+				attachment_store_get_background_filename (
+				E_ATTACHMENT_STORE (object)));
+			return;
+
+		case PROP_BACKGROUND_OPTIONS:
+			g_value_set_string (
+				value,
+				attachment_store_get_background_options (
+				E_ATTACHMENT_STORE (object)));
+			return;
+
+		case PROP_CURRENT_FOLDER:
+			g_value_set_string (
+				value,
+				e_attachment_store_get_current_folder (
+				E_ATTACHMENT_STORE (object)));
+			return;
+
+		case PROP_NUM_ATTACHMENTS:
+			g_value_set_uint (
+				value,
+				e_attachment_store_get_num_attachments (
+				E_ATTACHMENT_STORE (object)));
+			return;
+
+		case PROP_NUM_DOWNLOADING:
+			g_value_set_uint (
+				value,
+				e_attachment_store_get_num_downloading (
+				E_ATTACHMENT_STORE (object)));
+			return;
+
+		case PROP_TOTAL_SIZE:
+			g_value_set_uint64 (
+				value,
+				e_attachment_store_get_total_size (
+				E_ATTACHMENT_STORE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_store_dispose (GObject *object)
+{
+	EAttachmentStorePrivate *priv;
+
+	priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+
+	g_hash_table_remove_all (priv->activity_index);
+	g_hash_table_remove_all (priv->attachment_index);
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_store_finalize (GObject *object)
+{
+	EAttachmentStorePrivate *priv;
+
+	priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->activity_index);
+	g_hash_table_destroy (priv->attachment_index);
+
+	g_free (priv->background_filename);
+	g_free (priv->background_options);
+	g_free (priv->current_folder);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_store_constructed (GObject *object)
+{
+	EAttachmentStorePrivate *priv;
+	GConfBridge *bridge;
+	const gchar *prop;
+	const gchar *key;
+
+	priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+	bridge = gconf_bridge_get ();
+
+	prop = "background-filename";
+	key = "/desktop/gnome/background/picture_filename";
+	gconf_bridge_bind_property (bridge, key, object, prop);
+
+	prop = "background-options";
+	key = "/desktop/gnome/background/picture_options";
+	gconf_bridge_bind_property (bridge, key, object, prop);
+}
+
+static void
+attachment_store_row_changed (GtkTreeModel *model,
+                              GtkTreePath *path,
+                              GtkTreeIter *iter)
+{
+	EAttachmentStorePrivate *priv;
+	EAttachment *attachment;
+	GtkIconTheme *icon_theme;
+	GdkPixbuf *large_pixbuf;
+	GdkPixbuf *small_pixbuf;
+	GIcon *icon;
+	const gchar *content_type;
+	const gchar *display_name;
+	const gchar *thumbnail_path;
+	gchar *content_description;
+	gchar *display_size;
+	gchar *icon_caption;
+	gint large_icon_size;
+	gint small_icon_size;
+	guint64 size;
+	gint column_id;
+	GError *error = NULL;
+
+	priv = E_ATTACHMENT_STORE_GET_PRIVATE (model);
+
+	if (priv->ignore_row_changed)
+		return;
+
+	icon_theme = gtk_icon_theme_get_default ();
+	gtk_icon_size_lookup (LARGE_ICON_SIZE, &large_icon_size, NULL);
+	gtk_icon_size_lookup (SMALL_ICON_SIZE, &small_icon_size, NULL);
+
+	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+	gtk_tree_model_get (model, iter, column_id, &attachment, -1);
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	content_type = e_attachment_get_content_type (attachment);
+	display_name = e_attachment_get_display_name (attachment);
+	thumbnail_path = e_attachment_get_thumbnail_path (attachment);
+	icon = e_attachment_get_icon (attachment);
+	size = e_attachment_get_size (attachment);
+
+	content_type = (content_type != NULL) ? content_type : "";
+	content_description = g_content_type_get_description (content_type);
+	display_size = g_format_size_for_display ((goffset) size);
+
+	if (size > 0)
+		icon_caption = g_strdup_printf (
+			"%s\n(%s)", display_name, display_size);
+	else
+		icon_caption = g_strdup (display_name);
+
+	/* Prefer the thumbnail if we have one. */
+	if (thumbnail_path != NULL) {
+		gint width = -1;
+		gint height = -1;
+
+		gdk_pixbuf_get_file_info (thumbnail_path, &width, &height);
+
+		large_pixbuf = gdk_pixbuf_new_from_file_at_scale (
+			thumbnail_path,
+			(width > height) ? large_icon_size : -1,
+			(width > height) ? -1 : large_icon_size,
+			TRUE, &error);
+
+		if (error != NULL) {
+			g_warning ("%s", error->message);
+			g_clear_error (&error);
+		}
+
+		small_pixbuf = gdk_pixbuf_new_from_file_at_scale (
+			thumbnail_path,
+			(width > height) ? small_icon_size : -1,
+			(width > height) ? -1 : small_icon_size,
+			TRUE, &error);
+
+		if (error != NULL) {
+			g_warning ("%s", error->message);
+			g_clear_error (&error);
+		}
+
+	/* Otherwise fall back to the icon theme. */
+	} else {
+		GtkIconInfo *icon_info = NULL;
+		const gchar *filename;
+
+		if (G_IS_ICON (icon))
+			icon_info = gtk_icon_theme_lookup_by_gicon (
+				icon_theme, icon, large_icon_size, 0);
+		if (icon_info == NULL)
+			icon_info = gtk_icon_theme_lookup_icon (
+				icon_theme, DEFAULT_ICON_NAME,
+				large_icon_size, 0);
+		g_return_if_fail (icon_info != NULL);
+
+		filename = gtk_icon_info_get_filename (icon_info);
+		large_pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+		gtk_icon_info_free (icon_info);
+
+		if (error != NULL) {
+			g_warning ("%s", error->message);
+			g_clear_error (&error);
+		}
+
+		icon_info = NULL;
+
+		if (G_IS_ICON (icon))
+			icon_info = gtk_icon_theme_lookup_by_gicon (
+				icon_theme, icon, small_icon_size, 0);
+		if (icon_info == NULL)
+			icon_info = gtk_icon_theme_lookup_icon (
+				icon_theme, DEFAULT_ICON_NAME,
+				small_icon_size, 0);
+		g_return_if_fail (icon_info != NULL);
+
+		filename = gtk_icon_info_get_filename (icon_info);
+		small_pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+		gtk_icon_info_free (icon_info);
+
+		if (error != NULL) {
+			g_warning ("%s", error->message);
+			g_clear_error (&error);
+		}
+	}
+
+	/* We're about to trigger another "row-changed"
+	 * signal, so this prevents infinite recursion. */
+	priv->ignore_row_changed = TRUE;
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (model), iter,
+		E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_description,
+		E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME, display_name,
+		E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION, icon_caption,
+		E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF, large_pixbuf,
+		E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF, small_pixbuf,
+		E_ATTACHMENT_STORE_COLUMN_SIZE, size,
+		-1);
+
+	priv->ignore_row_changed = FALSE;
+
+	if (large_pixbuf != NULL)
+		g_object_unref (large_pixbuf);
+
+	if (small_pixbuf != NULL)
+		g_object_unref (small_pixbuf);
+
+	g_free (content_description);
+	g_free (display_size);
+}
+
+static void
+attachment_store_class_init (EAttachmentStoreClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentStorePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_store_set_property;
+	object_class->get_property = attachment_store_get_property;
+	object_class->dispose = attachment_store_dispose;
+	object_class->finalize = attachment_store_finalize;
+	object_class->constructed = attachment_store_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_BACKGROUND_FILENAME,
+		g_param_spec_string (
+			"background-filename",
+			"Background Filename",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_BACKGROUND_OPTIONS,
+		g_param_spec_string (
+			"background-options",
+			"Background Options",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_FOLDER,
+		g_param_spec_string (
+			"current-folder",
+			"Current Folder",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_NUM_ATTACHMENTS,
+		g_param_spec_uint (
+			"num-attachments",
+			"Num Attachments",
+			NULL,
+			0,
+			G_MAXUINT,
+			0,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_NUM_DOWNLOADING,
+		g_param_spec_uint (
+			"num-downloading",
+			"Num Downloading",
+			NULL,
+			0,
+			G_MAXUINT,
+			0,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_TOTAL_SIZE,
+		g_param_spec_uint64 (
+			"total-size",
+			"Total Size",
+			NULL,
+			0,
+			G_MAXUINT64,
+			0,
+			G_PARAM_READABLE));
+}
+
+static void
+attachment_store_iface_init (GtkTreeModelIface *iface)
+{
+	iface->row_changed = attachment_store_row_changed;
+}
+
+static void
+attachment_store_init (EAttachmentStore *store)
+{
+	GType types[E_ATTACHMENT_STORE_NUM_COLUMNS];
+	GHashTable *activity_index;
+	GHashTable *attachment_index;
+	gint column = 0;
+
+	activity_index = g_hash_table_new_full (
+		g_direct_hash, g_direct_equal,
+		(GDestroyNotify) g_object_unref,
+		(GDestroyNotify) gtk_tree_row_reference_free);
+
+	attachment_index = g_hash_table_new_full (
+		g_direct_hash, g_direct_equal,
+		(GDestroyNotify) g_object_unref,
+		(GDestroyNotify) gtk_tree_row_reference_free);
+
+	store->priv = E_ATTACHMENT_STORE_GET_PRIVATE (store);
+	store->priv->activity_index = activity_index;
+	store->priv->attachment_index = attachment_index;
+
+	types[column++] = E_TYPE_ACTIVITY;	/* COLUMN_ACTIVITY */
+	types[column++] = E_TYPE_ATTACHMENT;	/* COLUMN_ATTACHMENT */
+	types[column++] = G_TYPE_STRING;	/* COLUMN_CONTENT_TYPE */
+	types[column++] = G_TYPE_STRING;	/* COLUMN_DISPLAY_NAME */
+	types[column++] = G_TYPE_STRING;	/* COLUMN_ICON_CAPTION */
+	types[column++] = GDK_TYPE_PIXBUF;	/* COLUMN_LARGE_PIXBUF */
+	types[column++] = GDK_TYPE_PIXBUF;	/* COLUMN_SMALL_PIXBUF */
+	types[column++] = G_TYPE_UINT64;	/* COLUMN_SIZE */
+
+	g_assert (column == E_ATTACHMENT_STORE_NUM_COLUMNS);
+
+	gtk_list_store_set_column_types (
+		GTK_LIST_STORE (store), G_N_ELEMENTS (types), types);
+}
+
+GType
+e_attachment_store_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentStoreClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_store_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EAttachmentStore),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_store_init,
+			NULL   /* value_table */
+		};
+
+		static const GInterfaceInfo iface_info = {
+			(GInterfaceInitFunc) attachment_store_iface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_LIST_STORE, "EAttachmentStore",
+			&type_info, 0);
+
+		g_type_add_interface_static (
+			type, GTK_TYPE_TREE_MODEL, &iface_info);
+	}
+
+	return type;
+}
+
+GtkTreeModel *
+e_attachment_store_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT_STORE, NULL);
+}
+
+void
+e_attachment_store_add_attachment (EAttachmentStore *store,
+                                   EAttachment *attachment)
+{
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	GFile *file;
+
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (store), &iter,
+		E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, attachment, -1);
+
+	model = GTK_TREE_MODEL (store);
+	path = gtk_tree_model_get_path (model, &iter);
+	reference = gtk_tree_row_reference_new (model, path);
+	gtk_tree_path_free (path);
+
+	g_hash_table_insert (
+		store->priv->attachment_index,
+		g_object_ref (attachment), reference);
+
+	file = e_attachment_get_file (attachment);
+
+	/* This lets the attachment tell us when to update. */
+	_e_attachment_set_reference (attachment, reference);
+
+	if (!g_file_is_native (file))
+		attachment_store_copy_async (store, attachment);
+
+	g_object_freeze_notify (G_OBJECT (store));
+	g_object_notify (G_OBJECT (store), "num-attachments");
+	g_object_notify (G_OBJECT (store), "total-size");
+	g_object_thaw_notify (G_OBJECT (store));
+}
+
+gboolean
+e_attachment_store_remove_attachment (EAttachmentStore *store,
+                                      EAttachment *attachment)
+{
+	GtkTreeRowReference *reference;
+	GHashTable *hash_table;
+	EActivity *activity;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), FALSE);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	hash_table = store->priv->attachment_index;
+	reference = g_hash_table_lookup (hash_table, attachment);
+
+	if (reference == NULL)
+		return FALSE;
+
+	if (!gtk_tree_row_reference_valid (reference)) {
+		g_hash_table_remove (hash_table, attachment);
+		return FALSE;
+	}
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+
+	gtk_tree_model_get (
+		model, &iter,
+		E_ATTACHMENT_STORE_COLUMN_ACTIVITY, &activity, -1);
+
+	if (activity != NULL) {
+		/* Cancel the file transfer. */
+		e_activity_cancel (activity);
+		g_object_unref (activity);
+	}
+
+	gtk_list_store_remove (GTK_LIST_STORE (store), &iter);
+	g_hash_table_remove (hash_table, attachment);
+
+	g_object_freeze_notify (G_OBJECT (store));
+	g_object_notify (G_OBJECT (store), "num-attachments");
+	g_object_notify (G_OBJECT (store), "total-size");
+	g_object_thaw_notify (G_OBJECT (store));
+
+	return TRUE;
+}
+
+void
+e_attachment_store_add_to_multipart (EAttachmentStore *store,
+                                     CamelMultipart *multipart,
+                                     const gchar *default_charset)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+	g_return_if_fail (CAMEL_MULTIPART (multipart));
+
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	while (valid) {
+		EAttachment *attachment;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+
+		e_attachment_add_to_multipart (
+			attachment, multipart, default_charset);
+
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+}
+
+const gchar *
+e_attachment_store_get_current_folder (EAttachmentStore *store)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL);
+
+	return store->priv->current_folder;
+}
+
+void
+e_attachment_store_set_current_folder (EAttachmentStore *store,
+                                       const gchar *current_folder)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+	if (current_folder == NULL)
+		current_folder = g_get_home_dir ();
+
+	g_free (store->priv->current_folder);
+	store->priv->current_folder = g_strdup (current_folder);
+
+	g_object_notify (G_OBJECT (store), "current-folder");
+}
+
+guint
+e_attachment_store_get_num_attachments (EAttachmentStore *store)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+	return g_hash_table_size (store->priv->attachment_index);
+}
+
+guint
+e_attachment_store_get_num_downloading (EAttachmentStore *store)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+	return g_hash_table_size (store->priv->activity_index);
+}
+
+guint64
+e_attachment_store_get_total_size (EAttachmentStore *store)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	guint64 total_size = 0;
+	gboolean valid;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	while (valid) {
+		EAttachment *attachment;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		total_size += e_attachment_get_size (attachment);
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	return total_size;
+}
+
+gint
+e_attachment_store_run_file_chooser_dialog (EAttachmentStore *store,
+                                            GtkWidget *dialog)
+{
+	GtkFileChooser *file_chooser;
+	gint response = GTK_RESPONSE_NONE;
+	const gchar *current_folder;
+	gboolean update_folder;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), response);
+	g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
+
+	file_chooser = GTK_FILE_CHOOSER (dialog);
+	current_folder = e_attachment_store_get_current_folder (store);
+	gtk_file_chooser_set_current_folder (file_chooser, current_folder);
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	update_folder =
+		(response == GTK_RESPONSE_ACCEPT) ||
+		(response == GTK_RESPONSE_OK) ||
+		(response == GTK_RESPONSE_YES) ||
+		(response == GTK_RESPONSE_APPLY);
+
+	if (update_folder) {
+		gchar *folder;
+
+		folder = gtk_file_chooser_get_current_folder (file_chooser);
+		e_attachment_store_set_current_folder (store, folder);
+		g_free (folder);
+	}
+
+	return response;
+}
+
+void
+e_attachment_store_run_load_dialog (EAttachmentStore *store,
+                                    GtkWindow *parent)
+{
+	GtkFileChooser *file_chooser;
+	GtkWidget *dialog;
+	GtkWidget *option;
+	GSList *files, *iter;
+	const gchar *disposition;
+	gboolean active;
+	gint response;
+
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+	dialog = gtk_file_chooser_dialog_new (
+		_("Add Attachment"), parent,
+		GTK_FILE_CHOOSER_ACTION_OPEN,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		_("A_ttach"), GTK_RESPONSE_OK, NULL);
+
+	file_chooser = GTK_FILE_CHOOSER (dialog);
+	gtk_file_chooser_set_local_only (file_chooser, FALSE);
+	gtk_file_chooser_set_select_multiple (file_chooser, TRUE);
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+	gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment");
+
+	option = gtk_check_button_new_with_mnemonic (
+		_("_Suggest automatic display of attachment"));
+	gtk_file_chooser_set_extra_widget (file_chooser, option);
+	gtk_widget_show (option);
+
+	response = e_attachment_store_run_file_chooser_dialog (store, dialog);
+
+	if (response != GTK_RESPONSE_OK)
+		goto exit;
+
+	files = gtk_file_chooser_get_files (file_chooser);
+	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
+	disposition = active ? "inline" : "attachment";
+
+	for (iter = files; iter != NULL; iter = g_slist_next (iter)) {
+		EAttachment *attachment;
+		GFile *file = iter->data;
+
+		attachment = e_attachment_new ();
+		e_attachment_set_file (attachment, file);
+		e_attachment_store_add_attachment (store, attachment);
+		g_object_unref (attachment);
+	}
+
+	g_slist_foreach (files, (GFunc) g_object_unref, NULL);
+	g_slist_free (files);
+
+exit:
+	gtk_widget_destroy (dialog);
+}
+
+void
+e_attachment_store_run_save_dialog (EAttachmentStore *store,
+                                    EAttachment *attachment,
+                                    GtkWindow *parent)
+{
+	GtkFileChooser *file_chooser;
+	GtkWidget *dialog;
+	GFile *file;
+	EActivity *activity;
+	const gchar *display_name;
+	gint response;
+
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	dialog = gtk_file_chooser_dialog_new (
+		_("Save Attachment"), parent,
+		GTK_FILE_CHOOSER_ACTION_SAVE,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
+
+	file_chooser = GTK_FILE_CHOOSER (dialog);
+	gtk_file_chooser_set_local_only (file_chooser, FALSE);
+	gtk_file_chooser_set_do_overwrite_confirmation (file_chooser, TRUE);
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+	gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment");
+
+	display_name = e_attachment_get_display_name (attachment);
+	if (display_name != NULL)
+		gtk_file_chooser_set_current_name (file_chooser, display_name);
+
+	response = e_attachment_store_run_file_chooser_dialog (store, dialog);
+
+	if (response != GTK_RESPONSE_OK)
+		goto exit;
+
+	file = gtk_file_chooser_get_file (file_chooser);
+	activity = e_file_activity_new (_("Saving attachment"));
+	e_attachment_save_async (
+		attachment, E_FILE_ACTIVITY (activity), file);
+	g_signal_emit (store, signals[NEW_ACTIVITY], 0, activity);
+	g_object_unref (activity);
+	g_object_unref (file);
+
+exit:
+	gtk_widget_destroy (dialog);
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-store.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-store.h	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,110 @@
+/*
+ * e-attachment-store.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_STORE_H
+#define E_ATTACHMENT_STORE_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_STORE \
+	(e_attachment_store_get_type ())
+#define E_ATTACHMENT_STORE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStore))
+#define E_ATTACHMENT_STORE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_STORE, EAttachmentStoreClass))
+#define E_IS_ATTACHMENT_STORE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_STORE))
+#define E_IS_ATTACHMENT_STORE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_STORE))
+#define E_ATTACHMENT_STORE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStoreClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentStore EAttachmentStore;
+typedef struct _EAttachmentStoreClass EAttachmentStoreClass;
+typedef struct _EAttachmentStorePrivate EAttachmentStorePrivate;
+
+struct _EAttachmentStore {
+	GtkListStore parent;
+	EAttachmentStorePrivate *priv;
+};
+
+struct _EAttachmentStoreClass {
+	GtkListStoreClass parent_class;
+};
+
+enum {
+	E_ATTACHMENT_STORE_COLUMN_ACTIVITY,	/* E_TYPE_ACTIVITY */
+	E_ATTACHMENT_STORE_COLUMN_ATTACHMENT,	/* E_TYPE_ATTACHMENT */
+	E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, /* G_TYPE_STRING */
+	E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME,	/* G_TYPE_STRING */
+	E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION,	/* G_TYPE_STRING */
+	E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF,	/* GDK_TYPE_PIXBUF */
+	E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF,	/* GDK_TYPE_PIXBUF */
+	E_ATTACHMENT_STORE_COLUMN_SIZE,		/* G_TYPE_UINT64 */
+	E_ATTACHMENT_STORE_NUM_COLUMNS
+};
+
+GType		e_attachment_store_get_type	(void);
+GtkTreeModel *	e_attachment_store_new		(void);
+void		e_attachment_store_add_attachment
+						(EAttachmentStore *store,
+						 EAttachment *attachment);
+gboolean	e_attachment_store_remove_attachment
+						(EAttachmentStore *store,
+						 EAttachment *attachment);
+void		e_attachment_store_add_to_multipart
+						(EAttachmentStore *store,
+						 CamelMultipart *multipart,
+						 const gchar *default_charset);
+const gchar *	e_attachment_store_get_current_folder
+						(EAttachmentStore *store);
+void		e_attachment_store_set_current_folder
+						(EAttachmentStore *store,
+						 const gchar *current_folder);
+guint		e_attachment_store_get_num_attachments
+						(EAttachmentStore *store);
+guint		e_attachment_store_get_num_downloading
+						(EAttachmentStore *store);
+guint64		e_attachment_store_get_total_size
+						(EAttachmentStore *store);
+gint		e_attachment_store_run_file_chooser_dialog
+						(EAttachmentStore *store,
+						 GtkWidget *dialog);
+void		e_attachment_store_run_load_dialog
+						(EAttachmentStore *store,
+						 GtkWindow *parent);
+void		e_attachment_store_run_save_dialog
+						(EAttachmentStore *store,
+						 EAttachment *attachment,
+						 GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_STORE_H */

Added: branches/kill-bonobo/widgets/misc/e-attachment-tree-view.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-tree-view.c	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,396 @@
+/*
+ * e-attachment-tree-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-tree-view.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "e-attachment.h"
+#include "e-attachment-store.h"
+#include "e-attachment-view.h"
+
+#define E_ATTACHMENT_TREE_VIEW_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewPrivate))
+
+struct _EAttachmentTreeViewPrivate {
+	EAttachmentViewPrivate view_priv;
+};
+
+static gpointer parent_class;
+
+static void
+attachment_tree_view_dispose (GObject *object)
+{
+	e_attachment_view_dispose (E_ATTACHMENT_VIEW (object));
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_tree_view_finalize (GObject *object)
+{
+	e_attachment_view_finalize (E_ATTACHMENT_VIEW (object));
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_tree_view_render_size (GtkTreeViewColumn *column,
+                                  GtkCellRenderer *renderer,
+                                  GtkTreeModel *model,
+                                  GtkTreeIter *iter)
+{
+	gchar *display_size;
+	gint column_id;
+	guint64 size;
+
+	column_id = E_ATTACHMENT_STORE_COLUMN_SIZE;
+	gtk_tree_model_get (model, iter, column_id, &size, -1);
+
+	display_size = g_format_size_for_display ((goffset) size);
+	g_object_set (renderer, "text", display_size, NULL);
+	g_free (display_size);
+}
+
+static gboolean
+attachment_tree_view_button_press_event (GtkWidget *widget,
+                                         GdkEventButton *event)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+		e_attachment_view_show_popup_menu (view, event);
+		return TRUE;
+	}
+
+	/* Chain up to parent's button_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		button_press_event (widget, event);
+}
+
+static gboolean
+attachment_tree_view_key_press_event (GtkWidget *widget,
+                                      GdkEventKey *event)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	if (event->keyval == GDK_Delete) {
+		e_attachment_view_remove_selected (view, TRUE);
+		return TRUE;
+	}
+
+	/* Chain up to parent's key_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		key_press_event (widget, event);
+}
+
+static gboolean
+attachment_tree_view_drag_motion (GtkWidget *widget,
+                                  GdkDragContext *context,
+                                  gint x,
+                                  gint y,
+                                  guint time)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+attachment_tree_view_drag_data_received (GtkWidget *widget,
+                                         GdkDragContext *context,
+                                         gint x,
+                                         gint y,
+                                         GtkSelectionData *selection,
+                                         guint info,
+                                         guint time)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	e_attachment_view_drag_data_received (
+		view, context, x, y, selection, info, time);
+}
+
+static gboolean
+attachment_tree_view_popup_menu (GtkWidget *widget)
+{
+	EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+	e_attachment_view_show_popup_menu (view, NULL);
+
+	return TRUE;
+}
+
+static EAttachmentViewPrivate *
+attachment_tree_view_get_private (EAttachmentView *view)
+{
+	EAttachmentTreeViewPrivate *priv;
+
+	priv = E_ATTACHMENT_TREE_VIEW_GET_PRIVATE (view);
+
+	return &priv->view_priv;
+}
+
+static EAttachmentStore *
+attachment_tree_view_get_store (EAttachmentView *view)
+{
+	GtkTreeView *tree_view;
+	GtkTreeModel *model;
+
+	tree_view = GTK_TREE_VIEW (view);
+	model = gtk_tree_view_get_model (tree_view);
+
+	return E_ATTACHMENT_STORE (model);
+}
+
+static GtkTreePath *
+attachment_tree_view_get_path_at_pos (EAttachmentView *view,
+                                      gint x,
+                                      gint y)
+{
+	GtkTreeView *tree_view;
+	GtkTreePath *path;
+	gboolean row_exists;
+
+	tree_view = GTK_TREE_VIEW (view);
+
+	row_exists = gtk_tree_view_get_path_at_pos (
+		tree_view, x, y, &path, NULL, NULL, NULL);
+
+	return row_exists ? path : NULL;
+}
+
+static GList *
+attachment_tree_view_get_selected_paths (EAttachmentView *view)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	return gtk_tree_selection_get_selected_rows (selection, NULL);
+}
+
+static gboolean
+attachment_tree_view_path_is_selected (EAttachmentView *view,
+                                       GtkTreePath *path)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	return gtk_tree_selection_path_is_selected (selection, path);
+}
+
+static void
+attachment_tree_view_select_path (EAttachmentView *view,
+                                  GtkTreePath *path)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	gtk_tree_selection_select_path (selection, path);
+}
+
+static void
+attachment_tree_view_unselect_path (EAttachmentView *view,
+                                    GtkTreePath *path)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	gtk_tree_selection_unselect_path (selection, path);
+}
+
+static void
+attachment_tree_view_select_all (EAttachmentView *view)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	gtk_tree_selection_select_all (selection);
+}
+
+static void
+attachment_tree_view_unselect_all (EAttachmentView *view)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	gtk_tree_selection_unselect_all (selection);
+}
+
+static void
+attachment_tree_view_class_init (EAttachmentTreeViewClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentViewPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->dispose = attachment_tree_view_dispose;
+	object_class->finalize = attachment_tree_view_finalize;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->button_press_event = attachment_tree_view_button_press_event;
+	widget_class->key_press_event = attachment_tree_view_key_press_event;
+	widget_class->drag_motion = attachment_tree_view_drag_motion;
+	widget_class->drag_data_received = attachment_tree_view_drag_data_received;
+	widget_class->popup_menu = attachment_tree_view_popup_menu;
+}
+
+static void
+attachment_tree_view_iface_init (EAttachmentViewIface *iface)
+{
+	iface->get_private = attachment_tree_view_get_private;
+	iface->get_store = attachment_tree_view_get_store;
+
+	iface->get_path_at_pos = attachment_tree_view_get_path_at_pos;
+	iface->get_selected_paths = attachment_tree_view_get_selected_paths;
+	iface->path_is_selected = attachment_tree_view_path_is_selected;
+	iface->select_path = attachment_tree_view_select_path;
+	iface->unselect_path = attachment_tree_view_unselect_path;
+	iface->select_all = attachment_tree_view_select_all;
+	iface->unselect_all = attachment_tree_view_unselect_all;
+}
+
+static void
+attachment_tree_view_init (EAttachmentTreeView *tree_view)
+{
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	tree_view->priv = E_ATTACHMENT_TREE_VIEW_GET_PRIVATE (tree_view);
+
+	e_attachment_view_init (E_ATTACHMENT_VIEW (tree_view));
+
+	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_expand (column, TRUE);
+	gtk_tree_view_column_set_spacing (column, 3);
+	gtk_tree_view_column_set_title (column, _("Name"));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+
+	gtk_tree_view_column_add_attribute (
+		column, renderer, "pixbuf",
+		E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+	gtk_tree_view_column_add_attribute (
+		column, renderer, "text",
+		E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME);
+
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_title (column, _("Size"));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+	gtk_tree_view_column_set_cell_data_func (
+		column, renderer, (GtkTreeCellDataFunc)
+		attachment_tree_view_render_size, NULL, NULL);
+
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_title (column, _("Type"));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+	gtk_tree_view_column_add_attribute (
+		column, renderer, "text",
+		E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE);
+}
+
+GType
+e_attachment_tree_view_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentTreeViewClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_tree_view_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EAttachmentTreeView),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_tree_view_init,
+			NULL   /* value_table */
+		};
+
+		static const GInterfaceInfo iface_info = {
+			(GInterfaceInitFunc) attachment_tree_view_iface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_TREE_VIEW, "EAttachmentTreeView",
+			&type_info, 0);
+
+		g_type_add_interface_static (
+			type, E_TYPE_ATTACHMENT_VIEW, &iface_info);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_attachment_tree_view_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT_TREE_VIEW, NULL);
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-tree-view.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-tree-view.h	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,66 @@
+/*
+ * e-attachment-tree-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_TREE_VIEW_H
+#define E_ATTACHMENT_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_TREE_VIEW \
+	(e_attachment_tree_view_get_type ())
+#define E_ATTACHMENT_TREE_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeView))
+#define E_ATTACHMENT_TREE_VIEW_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewClass))
+#define E_IS_ATTACHMENT_TREE_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_TREE_VIEW))
+#define E_IS_ATTACHMENT_TREE_VIEW_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_TREE_VIEW))
+#define E_ATTACHMENT_TREE_VIEW_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentTreeView EAttachmentTreeView;
+typedef struct _EAttachmentTreeViewClass EAttachmentTreeViewClass;
+typedef struct _EAttachmentTreeViewPrivate EAttachmentTreeViewPrivate;
+
+struct _EAttachmentTreeView {
+	GtkTreeView parent;
+	EAttachmentTreeViewPrivate *priv;
+};
+
+struct _EAttachmentTreeViewClass {
+	GtkTreeViewClass parent_class;
+};
+
+GType		e_attachment_tree_view_get_type		(void);
+GtkWidget *	e_attachment_tree_view_new		(void);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_TREE_VIEW_H */

Added: branches/kill-bonobo/widgets/misc/e-attachment-view.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-view.c	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,1041 @@
+/*
+ * e-attachment-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-view.h"
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <camel/camel-stream-mem.h>
+
+#include "e-util/e-plugin-ui.h"
+#include "e-util/e-util.h"
+#include "e-attachment-dialog.h"
+
+enum {
+	DND_TYPE_MESSAGE_RFC822,
+	DND_TYPE_X_UID_LIST,
+	DND_TYPE_TEXT_URI_LIST,
+	DND_TYPE_NETSCAPE_URL,
+	DND_TYPE_TEXT_VCARD,
+	DND_TYPE_TEXT_CALENDAR
+};
+
+static GtkTargetEntry drop_types[] = {
+	{ "message/rfc822",	0, DND_TYPE_MESSAGE_RFC822 },
+	{ "x-uid-list",		0, DND_TYPE_X_UID_LIST },
+	{ "text/uri-list",	0, DND_TYPE_TEXT_URI_LIST },
+	{ "_NETSCAPE_URL",	0, DND_TYPE_NETSCAPE_URL },
+	{ "text/x-vcard",	0, DND_TYPE_TEXT_VCARD },
+	{ "text/calendar",	0, DND_TYPE_TEXT_CALENDAR }
+};
+
+/* The atoms need initialized at runtime. */
+static struct {
+	const gchar *target;
+	GdkAtom atom;
+	GdkDragAction actions;
+} drag_info[] = {
+	{ "message/rfc822",	NULL,	GDK_ACTION_COPY },
+	{ "x-uid-list",		NULL,	GDK_ACTION_COPY |
+					GDK_ACTION_MOVE |
+					GDK_ACTION_ASK },
+	{ "text/uri-list",	NULL,	GDK_ACTION_COPY },
+	{ "_NETSCAPE_URL",	NULL,	GDK_ACTION_COPY },
+	{ "text/x-vcard",	NULL,	GDK_ACTION_COPY },
+	{ "text/calendar",	NULL,	GDK_ACTION_COPY }
+};
+
+static const gchar *ui =
+"<ui>"
+"  <popup name='context'>"
+"    <menuitem action='save-as'/>"
+"    <menuitem action='set-background'/>"
+"    <menuitem action='remove'/>"
+"    <menuitem action='properties'/>"
+"    <placeholder name='custom-actions'/>"
+"    <separator/>"
+"    <menuitem action='add'/>"
+"    <separator/>"
+"    <placeholder name='open-actions'/>"
+"  </popup>"
+"  <popup name='dnd'>"
+"    <menuitem action='drag-copy'/>"
+"    <menuitem action='drag-move'/>"
+"    <separator/>"
+"    <menuitem action='drag-cancel'/>"
+"  </popup>"
+"</ui>";
+
+static void
+action_add_cb (GtkAction *action,
+               EAttachmentView *view)
+{
+	EAttachmentStore *store;
+	gpointer parent;
+
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	store = e_attachment_view_get_store (view);
+	e_attachment_store_run_load_dialog (store, parent);
+}
+
+static void
+action_drag_cancel_cb (GtkAction *action,
+                       EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	priv = e_attachment_view_get_private (view);
+	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+static void
+action_drag_copy_cb (GtkAction *action,
+                     EAttachmentView *view)
+{
+	e_attachment_view_drag_action (view, GDK_ACTION_COPY);
+}
+
+static void
+action_drag_move_cb (GtkAction *action,
+                     EAttachmentView *view)
+{
+	e_attachment_view_drag_action (view, GDK_ACTION_MOVE);
+}
+
+static void
+action_properties_cb (GtkAction *action,
+                      EAttachmentView *view)
+{
+	EAttachment *attachment;
+	GtkWidget *dialog;
+	GList *selected;
+	gpointer parent;
+
+	selected = e_attachment_view_get_selected_attachments (view);
+	g_return_if_fail (g_list_length (selected) == 1);
+	attachment = selected->data;
+
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	dialog = e_attachment_dialog_new (parent, attachment);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+
+	g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+	g_list_free (selected);
+}
+
+static void
+action_recent_cb (GtkAction *action,
+                  EAttachmentView *view)
+{
+	GtkRecentChooser *chooser;
+	EAttachmentStore *store;
+	EAttachment *attachment;
+	gchar *uri;
+
+	chooser = GTK_RECENT_CHOOSER (action);
+	store = e_attachment_view_get_store (view);
+
+	uri = gtk_recent_chooser_get_current_uri (chooser);
+	attachment = e_attachment_new_for_uri (uri);
+	e_attachment_store_add_attachment (store, attachment);
+	g_free (uri);
+}
+
+static void
+action_remove_cb (GtkAction *action,
+                  EAttachmentView *view)
+{
+	e_attachment_view_remove_selected (view, FALSE);
+}
+
+static void
+action_save_as_cb (GtkAction *action,
+                   EAttachmentView *view)
+{
+}
+
+static void
+action_set_background_cb (GtkAction *action,
+                          EAttachmentView *view)
+{
+}
+
+static GtkActionEntry standard_entries[] = {
+
+	{ "drag-cancel",
+	  NULL,
+	  N_("Cancel _Drag"),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_drag_cancel_cb) },
+
+	{ "drag-copy",
+	  NULL,
+	  N_("_Copy"),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_drag_copy_cb) },
+
+	{ "drag-move",
+	  NULL,
+	  N_("_Move"),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_drag_move_cb) },
+
+	{ "save-as",
+	  GTK_STOCK_SAVE_AS,
+	  NULL,
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_save_as_cb) },
+
+	{ "set-background",
+	  NULL,
+	  N_("Set as _Background"),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_set_background_cb) }
+};
+
+static GtkActionEntry editable_entries[] = {
+
+	{ "add",
+	  GTK_STOCK_ADD,
+	  N_("A_dd Attachment..."),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_add_cb) },
+
+	{ "properties",
+	  GTK_STOCK_PROPERTIES,
+	  NULL,
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_properties_cb) },
+
+	{ "remove",
+	  GTK_STOCK_REMOVE,
+	  NULL,
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_remove_cb) }
+};
+
+static void
+drop_message_rfc822 (EAttachmentView *view,
+                     GtkSelectionData *selection_data,
+                     EAttachmentStore *store,
+                     GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+	EAttachment *attachment;
+	CamelMimeMessage *message;
+	CamelDataWrapper *wrapper;
+	CamelStream *stream;
+	const gchar *data;
+	gboolean success = FALSE;
+	gboolean delete = FALSE;
+	gint length;
+
+	priv = e_attachment_view_get_private (view);
+
+	data = (const gchar *) gtk_selection_data_get_data (selection_data);
+	length = gtk_selection_data_get_length (selection_data);
+
+	stream = camel_stream_mem_new ();
+	camel_stream_write (stream, data, length);
+	camel_stream_reset (stream);
+
+	message = camel_mime_message_new ();
+	wrapper = CAMEL_DATA_WRAPPER (message);
+
+	if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1)
+		goto exit;
+
+	attachment = e_attachment_new_for_message (message);
+	e_attachment_store_add_attachment (store, attachment);
+	g_object_unref (attachment);
+
+	success = TRUE;
+	delete = (action == GDK_ACTION_MOVE);
+
+exit:
+	camel_object_unref (message);
+	camel_object_unref (stream);
+
+	gtk_drag_finish (priv->drag_context, success, delete, priv->time);
+}
+
+static void
+drop_netscape_url (EAttachmentView *view,
+                   GtkSelectionData *selection_data,
+                   EAttachmentStore *store,
+                   GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+	EAttachment *attachment;
+	const gchar *data;
+	gchar *copied_data;
+	gchar **strv;
+	gint length;
+
+	/* _NETSCAPE_URL is represented as "URI\nTITLE" */
+
+	priv = e_attachment_view_get_private (view);
+
+	data = (const gchar *) gtk_selection_data_get_data (selection_data);
+	length = gtk_selection_data_get_length (selection_data);
+
+	copied_data = g_strndup (data, length);
+	strv = g_strsplit (copied_data, "\n", 2);
+	g_free (copied_data);
+
+	attachment = e_attachment_new_for_uri (strv[0]);
+	e_attachment_store_add_attachment (store, attachment);
+	g_object_unref (attachment);
+
+	g_strfreev (strv);
+
+	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_text_uri_list (EAttachmentView *view,
+                    GtkSelectionData *selection_data,
+                    EAttachmentStore *store,
+                    GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+	gchar **uris;
+	gint ii;
+
+	priv = e_attachment_view_get_private (view);
+
+	uris = gtk_selection_data_get_uris (selection_data);
+
+	for (ii = 0; uris[ii] != NULL; ii++) {
+		EAttachment *attachment;
+
+		attachment = e_attachment_new_for_uri (uris[ii]);
+		e_attachment_store_add_attachment (store, attachment);
+		g_object_unref (attachment);
+	}
+
+	g_strfreev (uris);
+
+	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_text_generic (EAttachmentView *view,
+                   GtkSelectionData *selection_data,
+                   EAttachmentStore *store,
+                   GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+	EAttachment *attachment;
+	CamelMimePart *mime_part;
+	GdkAtom atom;
+	const gchar *data;
+	gchar *content_type;
+	gint length;
+
+	priv = e_attachment_view_get_private (view);
+
+	data = (const gchar *) gtk_selection_data_get_data (selection_data);
+	length = gtk_selection_data_get_length (selection_data);
+	atom = gtk_selection_data_get_data_type (selection_data);
+
+	mime_part = camel_mime_part_new ();
+
+	content_type = gdk_atom_name (atom);
+	camel_mime_part_set_content (mime_part, data, length, content_type);
+	camel_mime_part_set_disposition (mime_part, "inline");
+	g_free (content_type);
+
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
+	e_attachment_store_add_attachment (store, attachment);
+	g_object_unref (attachment);
+
+	camel_object_unref (mime_part);
+
+	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_x_uid_list (EAttachmentView *view,
+                 GtkSelectionData *selection_data,
+                 EAttachmentStore *store,
+                 GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+
+	/* FIXME  Ugh, this looks painful.  Requires mailer stuff. */
+
+	priv = e_attachment_view_get_private (view);
+
+	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+static void
+attachment_view_class_init (EAttachmentViewIface *iface)
+{
+	gint ii;
+
+	for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) {
+		const gchar *target = drag_info[ii].target;
+		drag_info[ii].atom = gdk_atom_intern (target, FALSE);
+	}
+}
+
+GType
+e_attachment_view_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentViewIface),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_view_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			0,     /* instance_size */
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_INTERFACE, "EAttachmentView", &type_info, 0);
+
+		g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET);
+	}
+
+	return type;
+}
+
+void
+e_attachment_view_init (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+	GtkUIManager *ui_manager;
+	GtkActionGroup *action_group;
+	const gchar *domain = GETTEXT_PACKAGE;
+	GError *error = NULL;
+
+	priv = e_attachment_view_get_private (view);
+
+	gtk_drag_dest_set (
+		GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL,
+		drop_types, G_N_ELEMENTS (drop_types),
+		GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+
+	ui_manager = gtk_ui_manager_new ();
+	priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+	priv->ui_manager = ui_manager;
+
+	action_group = gtk_action_group_new ("standard");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_action_group_add_actions (
+		action_group, standard_entries,
+		G_N_ELEMENTS (standard_entries), view);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	priv->standard_actions = action_group;
+
+	action_group = gtk_action_group_new ("editable");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_action_group_add_actions (
+		action_group, editable_entries,
+		G_N_ELEMENTS (editable_entries), view);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	priv->editable_actions = action_group;
+
+	action_group = gtk_action_group_new ("openwith");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	priv->openwith_actions = action_group;
+
+	/* Because we are loading from a hard-coded string, there is
+	 * no chance of I/O errors.  Failure here implies a malformed
+	 * UI definition.  Full stop. */
+	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+	if (error != NULL)
+		g_error ("%s", error->message);
+
+	e_plugin_ui_register_manager (ui_manager, "attachment-view", view);
+}
+
+void
+e_attachment_view_dispose (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	priv = e_attachment_view_get_private (view);
+
+	if (priv->ui_manager != NULL) {
+		g_object_unref (priv->ui_manager);
+		priv->ui_manager = NULL;
+	}
+
+	if (priv->standard_actions != NULL) {
+		g_object_unref (priv->standard_actions);
+		priv->standard_actions = NULL;
+	}
+
+	if (priv->editable_actions != NULL) {
+		g_object_unref (priv->editable_actions);
+		priv->editable_actions = NULL;
+	}
+
+	if (priv->openwith_actions != NULL) {
+		g_object_unref (priv->openwith_actions);
+		priv->openwith_actions = NULL;
+	}
+
+	if (priv->drag_context != NULL) {
+		g_object_unref (priv->drag_context);
+		priv->drag_context = NULL;
+	}
+}
+
+void
+e_attachment_view_finalize (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	priv = e_attachment_view_get_private (view);
+
+	if (priv->selection_data != NULL)
+		gtk_selection_data_free (priv->selection_data);
+}
+
+EAttachmentViewPrivate *
+e_attachment_view_get_private (EAttachmentView *view)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_val_if_fail (iface->get_private != NULL, NULL);
+
+	return iface->get_private (view);
+}
+
+EAttachmentStore *
+e_attachment_view_get_store (EAttachmentView *view)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_val_if_fail (iface->get_store != NULL, NULL);
+
+	return iface->get_store (view);
+}
+
+GList *
+e_attachment_view_get_selected_attachments (EAttachmentView *view)
+{
+	EAttachmentStore *store;
+	GtkTreeModel *model;
+	GList *selected, *item;
+	gint column_id;
+
+	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+	selected = e_attachment_view_get_selected_paths (view);
+	store = e_attachment_view_get_store (view);
+	model = GTK_TREE_MODEL (store);
+
+	/* Convert the GtkTreePaths to EAttachments. */
+	for (item = selected; item != NULL; item = item->next) {
+		EAttachment *attachment;
+		GtkTreePath *path;
+		GtkTreeIter iter;
+
+		path = item->data;
+
+		gtk_tree_model_get_iter (model, &iter, path);
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		gtk_tree_path_free (path);
+
+		item->data = attachment;
+	}
+
+	return selected;
+}
+void
+e_attachment_view_remove_selected (EAttachmentView *view,
+                                   gboolean select_next)
+{
+	EAttachmentStore *store;
+	GtkTreeModel *model;
+	GList *selected, *item;
+	gint column_id;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+	selected = e_attachment_view_get_selected_paths (view);
+	store = e_attachment_view_get_store (view);
+	model = GTK_TREE_MODEL (store);
+
+	for (item = selected; item != NULL; item = item->next) {
+		EAttachment *attachment;
+		GtkTreePath *path = item->data;
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter (model, &iter, path);
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		e_attachment_store_remove_attachment (store, attachment);
+		g_object_unref (attachment);
+	}
+
+	/* If we only removed one attachment, try to select another. */
+	if (select_next && g_list_length (selected) == 1) {
+		GtkTreePath *path = selected->data;
+
+		e_attachment_view_select_path (view, path);
+		if (!e_attachment_view_path_is_selected (view, path))
+			if (gtk_tree_path_prev (path))
+				e_attachment_view_select_path (view, path);
+	}
+
+	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+	g_list_free (selected);
+}
+
+GtkTreePath *
+e_attachment_view_get_path_at_pos (EAttachmentView *view,
+                                   gint x,
+                                   gint y)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_val_if_fail (iface->get_path_at_pos != NULL, NULL);
+
+	return iface->get_path_at_pos (view, x, y);
+}
+
+GList *
+e_attachment_view_get_selected_paths (EAttachmentView *view)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_val_if_fail (iface->get_selected_paths != NULL, NULL);
+
+	return iface->get_selected_paths (view);
+}
+
+gboolean
+e_attachment_view_path_is_selected (EAttachmentView *view,
+                                    GtkTreePath *path)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
+	g_return_val_if_fail (path != NULL, FALSE);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_val_if_fail (iface->path_is_selected != NULL, FALSE);
+
+	return iface->path_is_selected (view, path);
+}
+
+void
+e_attachment_view_select_path (EAttachmentView *view,
+                               GtkTreePath *path)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+	g_return_if_fail (path != NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_if_fail (iface->select_path != NULL);
+
+	iface->select_path (view, path);
+}
+
+void
+e_attachment_view_unselect_path (EAttachmentView *view,
+                                 GtkTreePath *path)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+	g_return_if_fail (path != NULL);
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_if_fail (iface->unselect_path != NULL);
+
+	iface->unselect_path (view, path);
+}
+
+void
+e_attachment_view_select_all (EAttachmentView *view)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_if_fail (iface->select_all != NULL);
+
+	iface->select_all (view);
+}
+
+void
+e_attachment_view_unselect_all (EAttachmentView *view)
+{
+	EAttachmentViewIface *iface;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+	g_return_if_fail (iface->unselect_all != NULL);
+
+	iface->unselect_all (view);
+}
+
+void
+e_attachment_view_sync_selection (EAttachmentView *view,
+                                  EAttachmentView *target)
+{
+	GList *selected, *iter;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (target));
+
+	selected = e_attachment_view_get_selected_paths (view);
+	e_attachment_view_unselect_all (target);
+
+	for (iter = selected; iter != NULL; iter = iter->next)
+		e_attachment_view_select_path (target, iter->data);
+
+	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+	g_list_free (selected);
+}
+
+void
+e_attachment_view_drag_action (EAttachmentView *view,
+                               GdkDragAction action)
+{
+	EAttachmentViewPrivate *priv;
+	GtkSelectionData *selection_data;
+	EAttachmentStore *store;
+	GdkAtom atom;
+	gchar *name;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	priv = e_attachment_view_get_private (view);
+
+	selection_data = priv->selection_data;
+	store = e_attachment_view_get_store (view);
+	atom = gtk_selection_data_get_data_type (selection_data);
+
+	switch (priv->info) {
+		case DND_TYPE_MESSAGE_RFC822:
+			drop_message_rfc822 (
+				view, selection_data, store, action);
+			return;
+
+		case DND_TYPE_NETSCAPE_URL:
+			drop_netscape_url (
+				view, selection_data, store, action);
+			return;
+
+		case DND_TYPE_TEXT_URI_LIST:
+			drop_text_uri_list (
+				view, selection_data, store, action);
+			return;
+
+		case DND_TYPE_TEXT_VCARD:
+		case DND_TYPE_TEXT_CALENDAR:
+			drop_text_generic (
+				view, selection_data, store, action);
+			return;
+
+		case DND_TYPE_X_UID_LIST:
+			drop_x_uid_list (
+				view, selection_data, store, action);
+			return;
+
+		default:
+			name = gdk_atom_name (atom);
+			g_warning ("Unknown drag type: %s", name);
+			g_free (name);
+			break;
+	}
+
+	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+gboolean
+e_attachment_view_drag_motion (EAttachmentView *view,
+                               GdkDragContext *context,
+                               gint x,
+                               gint y,
+                               guint time)
+{
+	GList *iter;
+	GdkDragAction actions = 0;
+	GdkDragAction chosen_action;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
+
+	for (iter = context->targets; iter != NULL; iter = iter->next) {
+		GdkAtom atom = iter->data;
+		gint ii;
+
+		for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
+			if (atom == drag_info[ii].atom)
+				actions |= drag_info[ii].actions;
+	}
+
+	actions &= context->actions;
+	chosen_action = context->suggested_action;
+
+	if (chosen_action == GDK_ACTION_ASK) {
+		GdkDragAction mask;
+
+		mask = GDK_ACTION_COPY | GDK_ACTION_MOVE;
+		if ((actions & mask) != mask)
+			chosen_action = GDK_ACTION_COPY;
+	}
+
+	gdk_drag_status (context, chosen_action, time);
+
+	return (chosen_action != 0);
+}
+
+void
+e_attachment_view_drag_data_received (EAttachmentView *view,
+                                      GdkDragContext *drag_context,
+                                      gint x,
+                                      gint y,
+                                      GtkSelectionData *selection_data,
+                                      guint info,
+                                      guint time)
+{
+	EAttachmentViewPrivate *priv;
+	GtkUIManager *ui_manager;
+	GdkDragAction action;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	priv = e_attachment_view_get_private (view);
+	ui_manager = e_attachment_view_get_ui_manager (view);
+
+	action = drag_context->action;
+
+	if (gtk_selection_data_get_data (selection_data) == NULL)
+		return;
+
+	if (gtk_selection_data_get_length (selection_data) == -1)
+		return;
+
+	if (priv->drag_context != NULL)
+		g_object_unref (priv->drag_context);
+
+	if (priv->selection_data != NULL)
+		gtk_selection_data_free (priv->selection_data);
+
+	priv->drag_context = g_object_ref (drag_context);
+	priv->selection_data = gtk_selection_data_copy (selection_data);
+	priv->info = info;
+	priv->time = time;
+
+	if (action == GDK_ACTION_ASK) {
+		GtkWidget *menu;
+
+		menu = gtk_ui_manager_get_widget (ui_manager, "/dnd");
+		g_return_if_fail (GTK_IS_MENU (menu));
+
+		gtk_menu_popup (
+			GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, time);
+	} else
+		e_attachment_view_drag_action (view, action);
+}
+
+GtkAction *
+e_attachment_view_get_action (EAttachmentView *view,
+                              const gchar *action_name)
+{
+	GtkUIManager *ui_manager;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+	g_return_val_if_fail (action_name != NULL, NULL);
+
+	ui_manager = e_attachment_view_get_ui_manager (view);
+
+	return e_lookup_action (ui_manager, action_name);
+}
+
+GtkActionGroup *
+e_attachment_view_get_action_group (EAttachmentView *view,
+                                    const gchar *group_name)
+{
+	GtkUIManager *ui_manager;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+	g_return_val_if_fail (group_name != NULL, NULL);
+
+	ui_manager = e_attachment_view_get_ui_manager (view);
+
+	return e_lookup_action_group (ui_manager, group_name);
+}
+
+GtkUIManager *
+e_attachment_view_get_ui_manager (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	priv = e_attachment_view_get_private (view);
+
+	return priv->ui_manager;
+}
+
+GtkAction *
+e_attachment_view_recent_action_new (EAttachmentView *view,
+                                     const gchar *action_name,
+                                     const gchar *action_label)
+{
+	GtkAction *action;
+	GtkRecentChooser *chooser;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+	g_return_val_if_fail (action_name != NULL, NULL);
+
+	action = gtk_recent_action_new (
+		action_name, action_label, NULL, NULL);
+	gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
+
+	chooser = GTK_RECENT_CHOOSER (action);
+	gtk_recent_chooser_set_show_icons (chooser, TRUE);
+	gtk_recent_chooser_set_show_not_found (chooser, FALSE);
+	gtk_recent_chooser_set_show_private (chooser, FALSE);
+	gtk_recent_chooser_set_show_tips (chooser, TRUE);
+	gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
+
+	g_signal_connect (
+		action, "item-activated",
+		G_CALLBACK (action_recent_cb), view);
+
+	return action;
+}
+
+void
+e_attachment_view_show_popup_menu (EAttachmentView *view,
+                                   GdkEventButton *event)
+{
+	GtkUIManager *ui_manager;
+	GtkWidget *menu;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	if (event != NULL) {
+		GtkTreePath *path;
+
+		path = e_attachment_view_get_path_at_pos (
+			view, event->x, event->y);
+		if (path != NULL) {
+			if (!e_attachment_view_path_is_selected (view, path)) {
+				e_attachment_view_unselect_all (view);
+				e_attachment_view_select_path (view, path);
+			}
+			gtk_tree_path_free (path);
+		} else
+			e_attachment_view_unselect_all (view);
+	}
+
+	e_attachment_view_update_actions (view);
+
+	ui_manager = e_attachment_view_get_ui_manager (view);
+	menu = gtk_ui_manager_get_widget (ui_manager, "/context");
+	g_return_if_fail (GTK_IS_MENU (menu));
+
+	if (event != NULL)
+		gtk_menu_popup (
+			GTK_MENU (menu), NULL, NULL, NULL, NULL,
+			event->button, event->time);
+	else
+		gtk_menu_popup (
+			GTK_MENU (menu), NULL, NULL, NULL, NULL,
+			0, gtk_get_current_event_time ());
+}
+
+void
+e_attachment_view_update_actions (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+	GFileInfo *file_info;
+	GtkAction *action;
+	GList *selected;
+	guint n_selected;
+	gboolean is_image;
+
+	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+	priv = e_attachment_view_get_private (view);
+	selected = e_attachment_view_get_selected_attachments (view);
+	n_selected = g_list_length (selected);
+
+	is_image = FALSE;
+	file_info = NULL;
+
+	if (n_selected == 1) {
+		EAttachment *attachment = selected->data;
+		file_info = e_attachment_get_file_info (attachment);
+		is_image = e_attachment_is_image (attachment);
+	}
+
+	action = e_attachment_view_get_action (view, "properties");
+	gtk_action_set_visible (action, n_selected == 1);
+
+	action = e_attachment_view_get_action (view, "remove");
+	gtk_action_set_visible (action, n_selected > 0);
+
+	action = e_attachment_view_get_action (view, "save-as");
+	gtk_action_set_visible (action, n_selected > 0);
+
+	action = e_attachment_view_get_action (view, "set-background");
+	gtk_action_set_visible (action, is_image);
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-view.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-view.h	Fri Mar 20 19:06:59 2009
@@ -0,0 +1,163 @@
+/*
+ * e-attachment-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_VIEW_H
+#define E_ATTACHMENT_VIEW_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment-store.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_VIEW \
+	(e_attachment_view_get_type ())
+#define E_ATTACHMENT_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_VIEW, EAttachmentView))
+#define E_ATTACHMENT_VIEW_IFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_VIEW, EAttachmentViewIface))
+#define E_IS_ATTACHMENT_VIEW(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_VIEW))
+#define E_IS_ATTACHMENT_VIEW_IFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_VIEW))
+#define E_ATTACHMENT_VIEW_GET_IFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_ATTACHMENT_VIEW, EAttachmentViewIface))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentView EAttachmentView;
+typedef struct _EAttachmentViewIface EAttachmentViewIface;
+typedef struct _EAttachmentViewPrivate EAttachmentViewPrivate;
+
+struct _EAttachmentViewIface {
+	GTypeInterface parent_iface;
+
+	/* General Methods */
+	EAttachmentViewPrivate *
+			(*get_private)		(EAttachmentView *view);
+	EAttachmentStore *
+			(*get_store)		(EAttachmentView *view);
+
+	/* Selection Methods */
+	GtkTreePath *	(*get_path_at_pos)	(EAttachmentView *view,
+						 gint x,
+						 gint y);
+	GList *		(*get_selected_paths)	(EAttachmentView *view);
+	gboolean	(*path_is_selected)	(EAttachmentView *view,
+						 GtkTreePath *path);
+	void		(*select_path)		(EAttachmentView *view,
+						 GtkTreePath *path);
+	void		(*unselect_path)	(EAttachmentView *view,
+						 GtkTreePath *path);
+	void		(*select_all)		(EAttachmentView *view);
+	void		(*unselect_all)		(EAttachmentView *view);
+};
+
+struct _EAttachmentViewPrivate {
+
+	/* Popup Menu Management */
+	GtkUIManager *ui_manager;
+	GtkActionGroup *standard_actions;
+	GtkActionGroup *editable_actions;
+	GtkActionGroup *openwith_actions;
+	guint merge_id;
+
+	/* Drag and Drop State */
+	GdkDragContext *drag_context;
+	GtkSelectionData *selection_data;
+	guint info;
+	guint time;
+};
+
+GType		e_attachment_view_get_type	(void);
+
+void		e_attachment_view_init		(EAttachmentView *view);
+void		e_attachment_view_dispose	(EAttachmentView *view);
+void		e_attachment_view_finalize	(EAttachmentView *view);
+
+EAttachmentViewPrivate *
+		e_attachment_view_get_private	(EAttachmentView *view);
+EAttachmentStore *
+		e_attachment_view_get_store	(EAttachmentView *view);
+GList *		e_attachment_view_get_selected_attachments
+						(EAttachmentView *view);
+void		e_attachment_view_remove_selected
+						(EAttachmentView *view,
+						 gboolean select_next);
+
+/* Selection Management */
+GtkTreePath *	e_attachment_view_get_path_at_pos
+						(EAttachmentView *view,
+						 gint x,
+						 gint y);
+GList *		e_attachment_view_get_selected_paths
+						(EAttachmentView *view);
+gboolean	e_attachment_view_path_is_selected
+						(EAttachmentView *view,
+						 GtkTreePath *path);
+void		e_attachment_view_select_path	(EAttachmentView *view,
+						 GtkTreePath *path);
+void		e_attachment_view_unselect_path	(EAttachmentView *view,
+						 GtkTreePath *path);
+void		e_attachment_view_select_all	(EAttachmentView *view);
+void		e_attachment_view_unselect_all	(EAttachmentView *view);
+void		e_attachment_view_sync_selection(EAttachmentView *view,
+						 EAttachmentView *target);
+
+/* Drag and Drop Support */
+void		e_attachment_view_drag_action	(EAttachmentView *view,
+						 GdkDragAction action);
+gboolean	e_attachment_view_drag_motion	(EAttachmentView *view,
+						 GdkDragContext *context,
+						 gint x,
+						 gint y,
+						 guint time);
+void		e_attachment_view_drag_data_received
+						(EAttachmentView *view,
+						 GdkDragContext *context,
+						 gint x,
+						 gint y,
+						 GtkSelectionData *selection,
+						 guint info,
+						 guint time);
+
+/* Popup Menu Management */
+GtkAction *	e_attachment_view_get_action	(EAttachmentView *view,
+						 const gchar *action_name);
+GtkActionGroup *e_attachment_view_get_action_group
+						(EAttachmentView *view,
+						 const gchar *group_name);
+GtkUIManager *	e_attachment_view_get_ui_manager(EAttachmentView *view);
+GtkAction *	e_attachment_view_recent_action_new
+						(EAttachmentView *view,
+						 const gchar *action_name,
+						 const gchar *action_label);
+void		e_attachment_view_show_popup_menu
+						(EAttachmentView *view,
+						 GdkEventButton *event);
+void		e_attachment_view_update_actions(EAttachmentView *view);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_VIEW_H */

Modified: branches/kill-bonobo/widgets/misc/e-attachment.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment.c	Fri Mar 20 19:06:59 2009
@@ -1,4 +1,5 @@
 /*
+ * e-attachment.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -14,81 +15,275 @@
  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
  *
  *
- * Authors:
- *			Ettore Perazzoli <ettore ximian com>
- *          Jeffrey Stedfast <fejj ximian com>
- *	     	Srinivasa Ragavan <sragavan novell com>
- *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include "e-attachment.h"
-#include "e-attachment-dialog.h"
 
-#ifdef G_OS_WIN32
-/* Include <windows.h> early (as the gio stuff below will
- * include it anyway, sigh) to workaround the DATADIR problem.
- * <windows.h> (and the headers it includes) stomps all over the
- * namespace like a baboon on crack, and especially the DATADIR enum
- * in objidl.h causes problems.
- */
-#undef DATADIR
-#define DATADIR crap_DATADIR
-#include <windows.h>
-#undef DATADIR
-#endif
-
-#include <sys/stat.h>
-#include <string.h>
 #include <errno.h>
-
-#include <camel/camel.h>
-
 #include <glib/gi18n.h>
-#include <glib/gstdio.h>
-
-#include <libebook/e-vcard.h>
+#include <camel/camel-iconv.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-vfs.h>
 
 #include "e-util/e-util.h"
-#include "e-util/e-error.h"
-#include "e-util/e-mktemp.h"
-#include "e-util/e-util-private.h"
 
 #define E_ATTACHMENT_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
 
+/* Attributes needed by EAttachmentStore, et al. */
+#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*"
+
 struct _EAttachmentPrivate {
-	gchar *filename;
-	gchar *description;
+	GFile *file;
+	GFileInfo *file_info;
+	GCancellable *cancellable;
+	CamelMimePart *mime_part;
 	gchar *disposition;
-	gchar *mime_type;
 
-	GdkPixbuf *thumbnail;
-	CamelMimePart *mime_part;
+	/* This is a reference to our row in an EAttachmentStore,
+	 * serving as a means of broadcasting "row-changed" signals.
+	 * If we are removed from the store, we lazily free the
+	 * reference when it is found to be to be invalid. */
+	GtkTreeRowReference *reference;
 };
 
 enum {
 	PROP_0,
-	PROP_DESCRIPTION,
 	PROP_DISPOSITION,
-	PROP_FILENAME,
-	PROP_THUMBNAIL
-};
-
-enum {
-	CHANGED,
-	UPDATE,
-	LAST_SIGNAL
+	PROP_FILE,
+	PROP_FILE_INFO,
+	PROP_MIME_PART
 };
 
 static gpointer parent_class;
-static guint signals[LAST_SIGNAL];
+
+static void
+attachment_notify_model (EAttachment *attachment)
+{
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	reference = attachment->priv->reference;
+
+	if (reference == NULL)
+		return;
+
+	/* Free the reference if it's no longer valid.
+	 * It means we've been removed from the store. */
+	if (!gtk_tree_row_reference_valid (reference)) {
+		gtk_tree_row_reference_free (reference);
+		attachment->priv->reference = NULL;
+		return;
+	}
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_row_changed (model, path, &iter);
+	g_object_notify (G_OBJECT (model), "total-size");
+
+	gtk_tree_path_free (path);
+}
+
+static gchar *
+attachment_get_default_charset (void)
+{
+	GConfClient *client;
+	const gchar *key;
+	gchar *charset;
+
+	/* XXX This function doesn't really belong here. */
+
+	client = gconf_client_get_default ();
+	key = "/apps/evolution/mail/composer/charset";
+	charset = gconf_client_get_string (client, key, NULL);
+	if (charset == NULL || *charset == '\0') {
+		g_free (charset);
+		key = "/apps/evolution/mail/format/charset";
+		charset = gconf_client_get_string (client, key, NULL);
+		if (charset == NULL || *charset == '\0') {
+			g_free (charset);
+			charset = NULL;
+		}
+	}
+	g_object_unref (client);
+
+	if (charset == NULL)
+		charset = g_strdup (camel_iconv_locale_charset ());
+
+	if (charset == NULL)
+		charset = g_strdup ("us-ascii");
+
+	return charset;
+}
+
+static void
+attachment_set_file_info (EAttachment *attachment,
+                          GFileInfo *file_info)
+{
+	GCancellable *cancellable;
+
+	cancellable = attachment->priv->cancellable;
+
+	/* Cancel any query operations in progress. */
+	if (!g_cancellable_is_cancelled (cancellable)) {
+		g_cancellable_cancel (cancellable);
+		g_cancellable_reset (cancellable);
+	}
+
+	if (file_info != NULL)
+		g_object_ref (file_info);
+
+	if (attachment->priv->file_info != NULL)
+		g_object_unref (attachment->priv->file_info);
+
+	attachment->priv->file_info = file_info;
+
+	g_object_notify (G_OBJECT (attachment), "file-info");
+
+	attachment_notify_model (attachment);
+}
+
+static void
+attachment_reset (EAttachment *attachment)
+{
+	GCancellable *cancellable;
+
+	cancellable = attachment->priv->cancellable;
+
+	g_object_freeze_notify (G_OBJECT (attachment));
+
+	/* Cancel any query operations in progress. */
+	if (!g_cancellable_is_cancelled (cancellable)) {
+		g_cancellable_cancel (cancellable);
+		g_cancellable_reset (cancellable);
+	}
+
+	if (attachment->priv->file != NULL) {
+		g_object_notify (G_OBJECT (attachment), "file");
+		g_object_unref (attachment->priv->file);
+		attachment->priv->file = NULL;
+	}
+
+	if (attachment->priv->mime_part != NULL) {
+		g_object_notify (G_OBJECT (attachment), "mime-part");
+		g_object_unref (attachment->priv->mime_part);
+		attachment->priv->mime_part = NULL;
+	}
+
+	attachment_set_file_info (attachment, NULL);
+
+	g_object_thaw_notify (G_OBJECT (attachment));
+}
+
+static void
+attachment_file_info_ready_cb (GFile *file,
+                               GAsyncResult *result,
+                               EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	GError *error = NULL;
+
+	/* Even if we failed to obtain a GFileInfo, we still emit a
+	 * "notify::file-info" to signal the async operation finished. */
+	file_info = g_file_query_info_finish (file, result, &error);
+	attachment_set_file_info (attachment, file_info);
+
+	if (file_info != NULL)
+		g_object_unref (file_info);
+	else {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+}
+
+static void
+attachment_file_info_to_mime_part (EAttachment *attachment,
+                                   CamelMimePart *mime_part)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
+	const gchar *string;
+	gchar *allocated;
+
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info == NULL || mime_part == NULL)
+		return;
+
+	/* XXX Note that we skip "standard::size" here. */
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+	string = g_file_info_get_attribute_string (file_info, attribute);
+	allocated = g_content_type_get_mime_type (string);
+	camel_mime_part_set_content_type (mime_part, allocated);
+	g_free (allocated);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+	string = g_file_info_get_attribute_string (file_info, attribute);
+	camel_mime_part_set_filename (mime_part, string);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	string = g_file_info_get_attribute_string (file_info, attribute);
+	camel_mime_part_set_description (mime_part, string);
+
+	string = e_attachment_get_disposition (attachment);
+	camel_mime_part_set_disposition (mime_part, string);
+}
+
+static void
+attachment_mime_part_to_file_info (EAttachment *attachment)
+{
+	CamelContentType *content_type;
+	CamelMimePart *mime_part;
+	GFileInfo *file_info;
+	const gchar *attribute;
+	const gchar *string;
+	gchar *allocated;
+	guint64 v_uint64;
+
+	file_info = e_attachment_get_file_info (attachment);
+	mime_part = e_attachment_get_mime_part (attachment);
+
+	if (file_info == NULL || mime_part == NULL)
+		return;
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+	content_type = camel_mime_part_get_content_type (mime_part);
+	allocated = camel_content_type_simple (content_type);
+	if (allocated != NULL)
+		g_file_info_set_attribute_string (
+			file_info, attribute, allocated);
+	g_free (allocated);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+	string = camel_mime_part_get_filename (mime_part);
+	if (string != NULL)
+		g_file_info_set_attribute_string (
+			file_info, attribute, string);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	string = camel_mime_part_get_description (mime_part);
+	if (string != NULL)
+		g_file_info_set_attribute_string (
+			file_info, attribute, string);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_SIZE;
+	v_uint64 = camel_mime_part_get_content_size (mime_part);
+	g_file_info_set_attribute_uint64 (file_info, attribute, v_uint64);
+
+	string = camel_mime_part_get_disposition (mime_part);
+	e_attachment_set_disposition (attachment, string);
+}
 
 static void
 attachment_set_property (GObject *object,
@@ -97,28 +292,22 @@
                          GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_DESCRIPTION:
-			e_attachment_set_description (
-				E_ATTACHMENT (object),
-				g_value_get_string (value));
-			return;
-
 		case PROP_DISPOSITION:
 			e_attachment_set_disposition (
 				E_ATTACHMENT (object),
 				g_value_get_string (value));
 			return;
 
-		case PROP_FILENAME:
-			e_attachment_set_filename (
+		case PROP_FILE:
+			e_attachment_set_file (
 				E_ATTACHMENT (object),
-				g_value_get_string (value));
+				g_value_get_object (value));
 			return;
 
-		case PROP_THUMBNAIL:
-			e_attachment_set_thumbnail (
+		case PROP_MIME_PART:
+			e_attachment_set_mime_part (
 				E_ATTACHMENT (object),
-				g_value_get_object (value));
+				g_value_get_boxed (value));
 			return;
 	}
 
@@ -132,27 +321,27 @@
                          GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_DESCRIPTION:
-			g_value_set_string (
-				value, e_attachment_get_description (
-				E_ATTACHMENT (object)));
-			return;
-
 		case PROP_DISPOSITION:
 			g_value_set_string (
 				value, e_attachment_get_disposition (
 				E_ATTACHMENT (object)));
 			return;
 
-		case PROP_FILENAME:
-			g_value_set_string (
-				value, e_attachment_get_filename (
+		case PROP_FILE:
+			g_value_set_object (
+				value, e_attachment_get_file (
 				E_ATTACHMENT (object)));
 			return;
 
-		case PROP_THUMBNAIL:
+		case PROP_FILE_INFO:
 			g_value_set_object (
-				value, e_attachment_get_thumbnail (
+				value, e_attachment_get_file_info (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_MIME_PART:
+			g_value_set_boxed (
+				value, e_attachment_get_mime_part (
 				E_ATTACHMENT (object)));
 			return;
 	}
@@ -167,9 +356,20 @@
 
 	priv = E_ATTACHMENT_GET_PRIVATE (object);
 
-	if (priv->thumbnail != NULL) {
-		g_object_unref (priv->thumbnail);
-		priv->thumbnail = NULL;
+	if (priv->cancellable != NULL) {
+		g_cancellable_cancel (priv->cancellable);
+		g_object_unref (priv->cancellable);
+		priv->cancellable = NULL;
+	}
+
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->file_info != NULL) {
+		g_object_unref (priv->file_info);
+		priv->file_info = NULL;
 	}
 
 	if (priv->mime_part != NULL) {
@@ -177,6 +377,10 @@
 		priv->mime_part = NULL;
 	}
 
+	/* This accepts NULL arguments. */
+	gtk_tree_row_reference_free (priv->reference);
+	priv->reference = NULL;
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -184,20 +388,11 @@
 static void
 attachment_finalize (GObject *object)
 {
-	EAttachment *attachment = (EAttachment *) object;
-
-	if (attachment->cancellable) {
-		/* the operation is still running, so cancel it */
-		g_cancellable_cancel (attachment->cancellable);
-		attachment->cancellable = NULL;
-	}
+	EAttachmentPrivate *priv;
 
-	g_free (attachment->store_uri);
+	priv = E_ATTACHMENT_GET_PRIVATE (object);
 
-	g_free (attachment->priv->filename);
-	g_free (attachment->priv->description);
-	g_free (attachment->priv->disposition);
-	g_free (attachment->priv->mime_type);
+	g_free (priv->disposition);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -219,75 +414,52 @@
 
 	g_object_class_install_property (
 		object_class,
-		PROP_DESCRIPTION,
+		PROP_DISPOSITION,
 		g_param_spec_string (
-			"description",
-			"Description",
-			NULL,
+			"disposition",
+			"Disposition",
 			NULL,
+			"attachment",
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT));
 
 	g_object_class_install_property (
 		object_class,
-		PROP_DESCRIPTION,
-		g_param_spec_string (
-			"disposition",
-			"Disposition",
-			NULL,
+		PROP_FILE,
+		g_param_spec_object (
+			"file",
+			"File",
 			NULL,
+			G_TYPE_FILE,
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT));
 
 	g_object_class_install_property (
 		object_class,
-		PROP_DESCRIPTION,
-		g_param_spec_string (
-			"filename",
-			"Filename",
-			NULL,
+		PROP_FILE_INFO,
+		g_param_spec_object (
+			"file-info",
+			"File Info",
 			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
+			G_TYPE_FILE_INFO,
+			G_PARAM_READABLE));
 
 	g_object_class_install_property (
 		object_class,
-		PROP_THUMBNAIL,
-		g_param_spec_object (
-			"thumbnail",
-			"Thumbnail Image",
+		PROP_MIME_PART,
+		g_param_spec_boxed (
+			"mime-part",
+			"MIME Part",
 			NULL,
-			GDK_TYPE_PIXBUF,
+			E_TYPE_CAMEL_OBJECT,
 			G_PARAM_READWRITE));
-
-	signals[CHANGED] = g_signal_new (
-		"changed",
-		G_OBJECT_CLASS_TYPE (class),
-		G_SIGNAL_RUN_FIRST,
-		G_STRUCT_OFFSET (EAttachmentClass, changed),
-		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
-	signals[UPDATE] = g_signal_new (
-		"update",
-		G_OBJECT_CLASS_TYPE (class),
-		G_SIGNAL_RUN_FIRST,
-		G_STRUCT_OFFSET (EAttachmentClass, update),
-		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
 }
 
 static void
 attachment_init (EAttachment *attachment)
 {
 	attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
-
-	attachment->index = -1;
-	attachment->percentage = -1;
-	attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
-	attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
+	attachment->priv->cancellable = g_cancellable_new ();
 }
 
 GType
@@ -316,711 +488,845 @@
 	return type;
 }
 
-/**
- * file_ext_is:
- * @param filename: path for file
- * @param ext: desired extension, with a dot
- * @return if filename has extension ext or not
- **/
-
-static gboolean
-file_ext_is (const char *filename, const char *ext)
+EAttachment *
+e_attachment_new (void)
 {
-	int i, dot = -1;
+	return g_object_new (E_TYPE_ATTACHMENT, NULL);
+}
 
-	if (!filename || !ext)
-		return FALSE;
+EAttachment *
+e_attachment_new_for_path (const gchar *path)
+{
+	EAttachment *attachment;
+	GFile *file;
 
-	for (i = 0; filename[i]; i++) {
-		if (filename [i] == '.')
-			dot = i;
-	}
+	g_return_val_if_fail (path != NULL, NULL);
 
-	if (dot > 0) {
-		return 0 == g_ascii_strcasecmp (filename + dot, ext);
-	}
+	file = g_file_new_for_path (path);
+	attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+	g_object_unref (file);
 
-	return FALSE;
+	return attachment;
 }
 
-static char *
-attachment_guess_mime_type (const char *filename)
+EAttachment *
+e_attachment_new_for_uri (const gchar *uri)
 {
-	char *type;
-	gchar *content = NULL;
-
-	type = e_util_guess_mime_type (filename, TRUE);
-
-	if (type && strcmp (type, "text/directory") == 0 &&
-	    file_ext_is (filename, ".vcf") &&
-	    g_file_get_contents (filename, &content, NULL, NULL) &&
-	    content) {
-		EVCard *vc = e_vcard_new_from_string (content);
+	EAttachment *attachment;
+	GFile *file;
 
-		if (vc) {
-			g_free (type);
-			g_object_unref (G_OBJECT (vc));
+	g_return_val_if_fail (uri != NULL, NULL);
 
-			type = g_strdup ("text/x-vcard");
-		}
+	file = g_file_new_for_uri (uri);
+	attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+	g_object_unref (file);
 
-	}
+	return attachment;
+}
 
-	g_free (content);
+EAttachment *
+e_attachment_new_for_message (CamelMimeMessage *message)
+{
+	CamelDataWrapper *wrapper;
+	CamelMimePart *mime_part;
+	EAttachment *attachment;
+	GString *description;
+	const gchar *subject;
 
-	if (type) {
-		/* Check if returned mime_type is valid */
-		CamelContentType *ctype = camel_content_type_decode (type);
+	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
 
-		if (!ctype) {
-			g_free (type);
-			type = NULL;
-		} else
-			camel_content_type_unref (ctype);
-	}
+	mime_part = camel_mime_part_new ();
+	camel_mime_part_set_disposition (mime_part, "inline");
+	subject = camel_mime_message_get_subject (message);
+
+	description = g_string_new (_("Attached message"));
+	if (subject != NULL)
+		g_string_append_printf (description, " - %s", subject);
+	camel_mime_part_set_description (mime_part, description->str);
+	g_string_free (description, TRUE);
+
+	wrapper = CAMEL_DATA_WRAPPER (message);
+	camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+	camel_mime_part_set_content_type (mime_part, "message/rfc822");
+
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
+	camel_object_unref (mime_part);
 
-	return type;
+	return attachment;
 }
 
-
-/**
- * e_attachment_new:
- * @filename: filename to attach
- * @disposition: Content-Disposition of the attachment
- * @ex: exception
- *
- * Return value: the new attachment, or %NULL on error
- **/
-EAttachment *
-e_attachment_new (const char *filename, const char *disposition, CamelException *ex)
+void
+e_attachment_add_to_multipart (EAttachment *attachment,
+                               CamelMultipart *multipart,
+                               const gchar *default_charset)
 {
-	EAttachment *new;
-	CamelMimePart *part;
+	CamelContentType *content_type;
 	CamelDataWrapper *wrapper;
-	CamelStream *stream;
-	struct stat statbuf;
-	gchar *mime_type;
-	gchar *basename;
-	CamelURL *url;
+	CamelMimePart *mime_part;
 
-	g_return_val_if_fail (filename != NULL, NULL);
+	/* XXX EMsgComposer might be a better place for this function. */
 
-	if (g_stat (filename, &statbuf) < 0) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      filename, g_strerror (errno));
-		return NULL;
-	}
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
 
-	/* return if it's not a regular file */
-	if (!S_ISREG (statbuf.st_mode)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: not a regular file"),
-				      filename);
-		return NULL;
-	}
+	/* Still loading?  Too bad. */
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part == NULL)
+		return;
 
-	if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      filename, g_strerror (errno));
-		return NULL;
-	}
+	content_type = camel_mime_part_get_content_type (mime_part);
+	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 
-	if ((mime_type = attachment_guess_mime_type (filename))) {
-		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-		} else {
-			wrapper = camel_data_wrapper_new ();
-		}
+	if (CAMEL_IS_MULTIPART (wrapper))
+		goto exit;
 
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, mime_type);
-		g_free (mime_type);
-	} else {
-		wrapper = camel_data_wrapper_new ();
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-	}
+	/* For text content, determine the best encoding and character set. */
+	if (camel_content_type_is (content_type, "text", "*")) {
+		CamelTransferEncoding encoding;
+		CamelStreamFilter *filtered_stream;
+		CamelMimeFilterBestenc *filter;
+		CamelStream *stream;
+		const gchar *charset;
+
+		charset = camel_content_type_param (content_type, "charset");
+
+		/* Determine the best encoding by writing the MIME
+		 * part to a NULL stream with a "bestenc" filter. */
+		stream = camel_stream_null_new ();
+		filtered_stream = camel_stream_filter_new_with_stream (stream);
+		filter = camel_mime_filter_bestenc_new (
+			CAMEL_BESTENC_GET_ENCODING);
+		camel_stream_filter_add (
+			filtered_stream, CAMEL_MIME_FILTER (filter));
+		camel_data_wrapper_decode_to_stream (
+			wrapper, CAMEL_STREAM (filtered_stream));
+		camel_object_unref (filtered_stream);
+		camel_object_unref (stream);
+
+		/* Retrieve the best encoding from the filter. */
+		encoding = camel_mime_filter_bestenc_get_best_encoding (
+			filter, CAMEL_BESTENC_8BIT);
+		camel_mime_part_set_encoding (mime_part, encoding);
+		camel_object_unref (filter);
+
+		if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
+			/* The text fits within us-ascii, so this is safe.
+			 * FIXME Check that this isn't iso-2022-jp? */
+			default_charset = "us-ascii";
+
+		} else if (charset == NULL && default_charset == NULL) {
+			default_charset = attachment_get_default_charset ();
+			/* FIXME Check that this fits within the
+			 *       default_charset and if not, find one
+			 *       that does and/or allow the user to
+			 *       specify. */
+		}
 
-	camel_object_unref (stream);
+		if (charset == NULL) {
+			gchar *type;
 
-	part = camel_mime_part_new ();
-	camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
-	camel_object_unref (wrapper);
+			camel_content_type_set_param (
+				content_type, "charset", default_charset);
+			type = camel_content_type_format (content_type);
+			camel_mime_part_set_content_type (mime_part, type);
+			g_free (type);
+		}
 
-	camel_mime_part_set_disposition (part, disposition);
-	basename = g_path_get_basename (filename);
-	camel_mime_part_set_filename (part, basename);
+	/* Otherwise, unless it's a message/rfc822, Base64 encode it. */
+	} else if (!CAMEL_IS_MIME_MESSAGE (wrapper))
+		camel_mime_part_set_encoding (
+			mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
 
-#if 0
-	/* Note: Outlook 2002 is broken with respect to Content-Ids on
-           non-multipart/related parts, so as an interoperability
-           workaround, don't set a Content-Id on these parts. Fixes
-           bug #10032 */
-	/* set the Content-Id */
-	content_id = camel_header_msgid_generate ();
-	camel_mime_part_set_content_id (part, content_id);
-	g_free (content_id);
-#endif
+exit:
+	camel_multipart_add_part (multipart, mime_part);
+}
 
-	new = g_object_new (E_TYPE_ATTACHMENT, "filename", basename, NULL);
-	new->priv->mime_part = part;
-	new->size = statbuf.st_size;
-	new->guessed_type = TRUE;
-	new->cancellable = NULL;
-	new->is_available_local = TRUE;
-
-	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, filename);
-	new->store_uri = camel_url_to_string (url, 0);
-	camel_url_free (url);
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	return new;
+	return attachment->priv->disposition;
 }
 
+void
+e_attachment_set_disposition (EAttachment *attachment,
+                              const gchar *disposition)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
-typedef struct {
-	EAttachment *attachment;
-	char *filename;
-	char *uri;
-	GtkWindow *parent; /* for error dialog */
-
-	guint64 file_size; /* zero indicates unknown size */
-	GInputStream *istream; /* read from here ... */
-	GOutputStream *ostream; /* ...and write into this. */
-	gboolean was_error;
-	GCancellable *cancellable;
+	g_free (attachment->priv->disposition);
+	attachment->priv->disposition = g_strdup (disposition);
 
-	void *buffer; /* read into this, not more than buffer_size bytes */
-	gsize buffer_size;
-} DownloadInfo;
+	g_object_notify (G_OBJECT (attachment), "disposition");
+}
 
-static void
-download_info_free (DownloadInfo *download_info)
+GFile *
+e_attachment_get_file (EAttachment *attachment)
 {
-	/* if there was an error, then free attachment too */
-	if (download_info->was_error)
-		g_object_unref (download_info->attachment);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	if (download_info->ostream)
-		g_object_unref (download_info->ostream);
+	return attachment->priv->file;
+}
 
-	if (download_info->istream)
-		g_object_unref (download_info->istream);
+void
+e_attachment_set_file (EAttachment *attachment,
+                       GFile *file)
+{
+	GCancellable *cancellable;
 
-	if (download_info->cancellable)
-		g_object_unref (download_info->cancellable);
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
-	g_free (download_info->filename);
-	g_free (download_info->uri);
-	g_free (download_info->buffer);
-	g_free (download_info);
-}
+	g_object_freeze_notify (G_OBJECT (attachment));
 
-static void
-data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
-	DownloadInfo *download_info = (DownloadInfo *)user_data;
-	GError *error = NULL;
-	gssize read;
+	if (file != NULL) {
+		g_return_if_fail (G_IS_FILE (file));
+		g_object_ref (file);
+	}
 
-	g_return_if_fail (download_info != NULL);
+	attachment_reset (attachment);
+	attachment->priv->file = file;
 
-	if (g_cancellable_is_cancelled (download_info->cancellable)) {
-		/* finish the operation and close both streams */
-		g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL);
+	cancellable = attachment->priv->cancellable;
 
-		g_output_stream_close (download_info->ostream, NULL, NULL);
-		g_input_stream_close  (download_info->istream, NULL, NULL);
+	if (file != NULL)
+		g_file_query_info_async (
+			file, ATTACHMENT_QUERY,
+			G_FILE_QUERY_INFO_NONE,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback)
+			attachment_file_info_ready_cb,
+			attachment);
 
-		/* The only way how to get this canceled is in EAttachment's finalize method,
-		   and because the download_info_free free's the attachment on error,
-		   then do not consider cancellation as an error. */
-		download_info_free (download_info);
-		return;
-	}
+	g_object_notify (G_OBJECT (attachment), "file");
 
-	read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
+	g_object_thaw_notify (G_OBJECT (attachment));
+}
 
-	if (!error)
-		g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error);
+GFileInfo *
+e_attachment_get_file_info (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	if (error) {
-		download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED;
-		if (download_info->was_error)
-			e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL);
+	return attachment->priv->file_info;
+}
 
-		g_error_free (error);
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-		download_info->attachment->cancellable = NULL;
-		download_info_free (download_info);
-		return;
-	}
+	return attachment->priv->mime_part;
+}
 
-	if (read == 0) {
-		CamelException ex;
+void
+e_attachment_set_mime_part (EAttachment *attachment,
+                            CamelMimePart *mime_part)
+{
+	GFileInfo *file_info;
 
-		/* done with reading */
-		g_output_stream_close (download_info->ostream, NULL, NULL);
-		g_input_stream_close  (download_info->istream, NULL, NULL);
-
-		download_info->attachment->cancellable = NULL;
-
-		camel_exception_init (&ex);
-		e_attachment_build_remote_file (download_info->filename, download_info->attachment, &ex);
-
-		if (camel_exception_is_set (&ex)) {
-			download_info->was_error = TRUE;
-			e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL);
-			camel_exception_clear (&ex);
-		}
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
-		download_info->attachment->percentage = -1;
-		download_info->attachment->is_available_local = TRUE;
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+	g_object_freeze_notify (G_OBJECT (attachment));
 
-		download_info_free (download_info);
-		return;
-	} else 	if (download_info->file_size) {
-		download_info->attachment->percentage = read * 100 / download_info->file_size;
-		download_info->file_size -= MIN (download_info->file_size, read);
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
-	} else {
-		download_info->attachment->percentage = 0;
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+	if (mime_part != NULL) {
+		g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+		camel_object_ref (mime_part);
 	}
 
-	/* read next chunk */
-	g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+	attachment_reset (attachment);
+	attachment->priv->mime_part = mime_part;
+
+	file_info = g_file_info_new ();
+	attachment_set_file_info (attachment, file_info);
+	attachment_mime_part_to_file_info (attachment);
+	g_object_unref (file_info);
+
+	g_object_notify (G_OBJECT (attachment), "mime-part");
+
+	g_object_thaw_notify (G_OBJECT (attachment));
 }
 
-static gboolean
-download_to_local_path (DownloadInfo *download_info, CamelException *ex)
+const gchar *
+e_attachment_get_content_type (EAttachment *attachment)
 {
-	GError *error = NULL;
-	GFile *src = g_file_new_for_uri (download_info->uri);
-	GFile *des = g_file_new_for_path (download_info->filename);
-	gboolean res = FALSE;
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-	g_return_val_if_fail (src != NULL && des != NULL, FALSE);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+	attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+	file_info = e_attachment_get_file_info (attachment);
 
-	if (download_info->ostream && !error) {
-		GFileInfo *fi;
+	if (file_info == NULL)
+		return NULL;
 
-		fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+	return g_file_info_get_attribute_string (file_info, attribute);
+}
 
-		if (fi) {
-			download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE);
-			g_object_unref (fi);
-		} else {
-			download_info->file_size = 0;
-		}
+const gchar *
+e_attachment_get_display_name (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-		download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error));
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-		if (download_info->istream && !error) {
-			download_info->cancellable = g_cancellable_new ();
-			download_info->attachment->cancellable = download_info->cancellable;
-			download_info->buffer_size = 10240; /* max 10KB chunk */
-			download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size);
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+	file_info = e_attachment_get_file_info (attachment);
 
-			g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+	if (file_info == NULL)
+		return NULL;
 
-			res = TRUE;
-		}
-	}
+	return g_file_info_get_attribute_string (file_info, attribute);
+}
 
-	if (error) {
-		/* propagate error */
-		if (ex)
-			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message);
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-		g_error_free (error);
-		download_info->was_error = TRUE;
-		download_info_free (download_info);
-	}
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	file_info = e_attachment_get_file_info (attachment);
 
-	g_object_unref (src);
-	g_object_unref (des);
+	if (file_info == NULL)
+		return NULL;
 
-	return res;
+	return g_file_info_get_attribute_string (file_info, attribute);
 }
 
-EAttachment *
-e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, const char *disposition, const char *path, CamelException *ex)
+GIcon *
+e_attachment_get_icon (EAttachment *attachment)
 {
-	EAttachment *new;
-	DownloadInfo *download_info;
-	CamelURL *url;
-	char *base;
-	gchar *filename;
-
-	g_return_val_if_fail (uri != NULL, NULL);
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-	url = camel_url_new (uri, NULL);
-	base = g_path_get_basename (url->path);
-	camel_url_free (url);
-
-	filename = g_build_filename (path, base, NULL);
-
-	new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
-	new->size = 0;
-	new->guessed_type = FALSE;
-	new->cancellable = NULL;
-	new->is_available_local = FALSE;
-	new->percentage = 0;
-
-	g_free (base);
-
-	download_info = g_new0 (DownloadInfo, 1);
-	download_info->attachment = new;
-	download_info->filename = g_strdup (filename);
-	download_info->uri = g_strdup (uri);
-	download_info->parent = error_dlg_parent;
-	download_info->was_error = FALSE;
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	g_free (filename);
+	attribute = G_FILE_ATTRIBUTE_STANDARD_ICON;
+	file_info = e_attachment_get_file_info (attachment);
 
-	/* it frees all on the error, so do not free it twice */
-	if (!download_to_local_path (download_info, ex))
+	if (file_info == NULL)
 		return NULL;
 
-	return new;
+	return (GIcon *)
+		g_file_info_get_attribute_object (file_info, attribute);
 }
 
-
-void
-e_attachment_build_remote_file (const gchar *filename,
-                                EAttachment *attachment,
-                                CamelException *ex)
+const gchar *
+e_attachment_get_thumbnail_path (EAttachment *attachment)
 {
-	CamelMimePart *part;
-	CamelDataWrapper *wrapper;
-	CamelStream *stream;
-	struct stat statbuf;
-	const gchar *description;
-	const gchar *disposition;
-	gchar *mime_type;
-	gchar *basename;
-	CamelURL *url;
-
-	g_return_if_fail (filename != NULL);
-
-	if (g_stat (filename, &statbuf) == -1) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      filename, g_strerror (errno));
-		g_message ("Cannot attach file %s: %s\n", filename, g_strerror (errno));
-		return;
-	}
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-	/* return if it's not a regular file */
-	if (!S_ISREG (statbuf.st_mode)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: not a regular file"),
-				      filename);
-		g_message ("Cannot attach file %s: not a regular file", filename);
-		return;
-	}
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      filename, g_strerror (errno));
-		return;
-	}
+	attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH;
+	file_info = e_attachment_get_file_info (attachment);
 
-	if ((mime_type = attachment_guess_mime_type (filename))) {
-		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-		} else {
-			wrapper = camel_data_wrapper_new ();
-		}
+	if (file_info == NULL)
+		return NULL;
 
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, mime_type);
-		g_free (mime_type);
-	} else {
-		wrapper = camel_data_wrapper_new ();
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-	}
+	return g_file_info_get_attribute_byte_string (file_info, attribute);
+}
 
-	camel_object_unref (stream);
+guint64
+e_attachment_get_size (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
 
-	part = camel_mime_part_new ();
-	camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
-	camel_object_unref (wrapper);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0);
 
-	disposition = e_attachment_get_disposition (attachment);
-	camel_mime_part_set_disposition (part, disposition);
+	attribute = G_FILE_ATTRIBUTE_STANDARD_SIZE;
+	file_info = e_attachment_get_file_info (attachment);
 
-	if (e_attachment_get_filename (attachment) == NULL)
-		basename = g_path_get_basename (filename);
-	else
-		basename = g_path_get_basename (e_attachment_get_filename (attachment));
+	if (file_info == NULL)
+		return 0;
 
-	camel_mime_part_set_filename (part, filename);
+	return g_file_info_get_attribute_uint64 (file_info, attribute);
+}
 
-	description = e_attachment_get_description (attachment);
-	if (description != NULL) {
-		camel_mime_part_set_description (part, description);
-		e_attachment_set_description (attachment, NULL);
-	}
+gboolean
+e_attachment_is_image (EAttachment *attachment)
+{
+	const gchar *content_type;
 
-	attachment->priv->mime_part = part;
-	attachment->size = statbuf.st_size;
-	attachment->guessed_type = TRUE;
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
 
-	e_attachment_set_filename (attachment, basename);
+	content_type = e_attachment_get_content_type (attachment);
 
-	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, filename);
-	attachment->store_uri = camel_url_to_string (url, 0);
-	camel_url_free (url);
+	if (content_type == NULL)
+		return FALSE;
 
-	g_free (basename);
+	return g_content_type_is_a (content_type, "image");
 }
 
-
-/**
- * e_attachment_new_from_mime_part:
- * @part: a CamelMimePart
- *
- * Return value: a new EAttachment based on the mime part
- **/
-EAttachment *
-e_attachment_new_from_mime_part (CamelMimePart *part)
+gboolean
+e_attachment_is_rfc822 (EAttachment *attachment)
 {
-	EAttachment *new;
-	const gchar *filename;
+	const gchar *content_type;
 
-	g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
 
-	filename = camel_mime_part_get_filename (part);
+	content_type = e_attachment_get_content_type (attachment);
 
-	new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
-	camel_object_ref (part);
-	new->priv->mime_part = part;
-	new->guessed_type = FALSE;
-	new->is_available_local = TRUE;
-	new->size = camel_mime_part_get_content_size (part);
+	if (content_type == NULL)
+		return FALSE;
 
-	return new;
+	return g_content_type_equals (content_type, "message/rfc822");
 }
 
-void
-e_attachment_edit (EAttachment *attachment,
-                   GtkWindow *parent)
+static void
+attachment_save_file_cb (GFile *source,
+                         GAsyncResult *result,
+                         EActivity *activity)
 {
-	GtkWidget *dialog;
+	GError *error = NULL;
 
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	if (!g_file_copy_finish (source, result, &error)) {
+		e_activity_set_error (activity, error);
+		g_error_free (error);
+	}
 
-	dialog = e_attachment_dialog_new (parent, attachment);
-	gtk_dialog_run (GTK_DIALOG (dialog));
-	gtk_widget_destroy (dialog);
+	e_activity_complete (activity);
+	g_object_unref (activity);
 }
 
-const gchar *
-e_attachment_get_description (EAttachment *attachment)
+static gpointer
+attachment_save_part_thread (EActivity *activity)
 {
+	GObject *object;
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GOutputStream *output_stream;
+	EFileActivity *file_activity;
+	CamelDataWrapper *wrapper;
 	CamelMimePart *mime_part;
-	const gchar *description;
+	CamelStream *stream;
+	GError *error = NULL;
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	object = G_OBJECT (activity);
+	attachment = g_object_get_data (object, "attachment");
+	output_stream = g_object_get_data (object, "output-stream");
+
+	/* Last chance to cancel. */
+	file_activity = E_FILE_ACTIVITY (activity);
+	cancellable = e_file_activity_get_cancellable (file_activity);
+	if (g_cancellable_set_error_if_cancelled (cancellable, &error))
+		goto exit;
 
+	object = g_object_ref (output_stream);
+	stream = camel_stream_vfs_new_with_stream (object);
 	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		description = camel_mime_part_get_description (mime_part);
-	else 
-		description = attachment->priv->description;
-
-	return description;
-}
+	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 
-void
-e_attachment_set_description (EAttachment *attachment,
-                              const gchar *description)
-{
-	CamelMimePart *mime_part;
+	if (camel_data_wrapper_decode_to_stream (wrapper, stream) < 0)
+		g_set_error (
+			&error, G_IO_ERROR,
+			g_io_error_from_errno (errno),
+			g_strerror (errno));
+
+	else if (camel_stream_flush (stream) < 0)
+		g_set_error (
+			&error, G_IO_ERROR,
+			g_io_error_from_errno (errno),
+			g_strerror (errno));
 
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	camel_object_unref (stream);
 
-	g_free (attachment->priv->description);
-	attachment->priv->description = g_strdup (description);
+exit:
+	if (error != NULL) {
+		e_activity_set_error (activity, error);
+		g_error_free (error);
+	}
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		camel_mime_part_set_description (mime_part, description);
+	e_activity_complete_in_idle (activity);
+	g_object_unref (activity);
 
-	g_object_notify (G_OBJECT (attachment), "description");
+	return NULL;
 }
 
-const gchar *
-e_attachment_get_disposition (EAttachment *attachment)
+static void
+attachment_save_part_cb (GFile *destination,
+                         GAsyncResult *result,
+                         EActivity *activity)
 {
-	CamelMimePart *mime_part;
-	const gchar *disposition;
+	GFileOutputStream *output_stream;
+	GError *error = NULL;
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	output_stream = g_file_replace_finish (destination, result, &error);
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		disposition = camel_mime_part_get_disposition (mime_part);
-	else
-		disposition = attachment->priv->disposition;
+	if (output_stream != NULL) {
+		g_object_set_data_full (
+			G_OBJECT (activity),
+			"output-stream", output_stream,
+			(GDestroyNotify) g_object_unref);
+		g_thread_create (
+			(GThreadFunc) attachment_save_part_thread,
+			activity, FALSE, &error);
+	}
+
+	if (error != NULL) {
+		e_activity_set_error (activity, error);
+		e_activity_complete (activity);
+		g_object_unref (activity);
+		g_error_free (error);
+	}
 
-	return disposition;
 }
 
 void
-e_attachment_set_disposition (EAttachment *attachment,
-                              const gchar *disposition)
+e_attachment_save_async (EAttachment *attachment,
+                         EFileActivity *file_activity,
+                         GFile *destination)
 {
+	GFileProgressCallback progress_callback;
+	GCancellable *cancellable;
 	CamelMimePart *mime_part;
+	GFile *source;
 
 	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (G_IS_FILE (destination));
+	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
 
-	g_free (attachment->priv->disposition);
-	attachment->priv->disposition = g_strdup (disposition);
+	/* The attachment content is either a GFile (on disk) or a
+	 * CamelMimePart (in memory).  Each is saved differently. */
 
+	source = e_attachment_get_file (attachment);
 	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		camel_mime_part_set_disposition (mime_part, disposition);
+	g_return_if_fail (source != NULL || mime_part != NULL);
 
-	g_object_notify (G_OBJECT (attachment), "disposition");
+	cancellable = e_file_activity_get_cancellable (file_activity);
+	progress_callback = e_file_activity_progress;
+
+	/* GFile is the easier, but probably less common case.  The
+	 * attachment already references an on-disk file, so we can
+	 * just use GIO to copy it asynchronously.
+	 *
+	 * We use G_FILE_COPY_OVERWRITE because the user should have
+	 * already confirmed the overwrite through the save dialog. */
+	if (G_IS_FILE (source))
+		g_file_copy_async (
+			source, destination,
+			G_FILE_COPY_OVERWRITE,
+			G_PRIORITY_DEFAULT, cancellable,
+			progress_callback, file_activity,
+			(GAsyncReadyCallback) attachment_save_file_cb,
+			g_object_ref (file_activity));
+
+	/* CamelMimePart can only be decoded to a file synchronously, so
+	 * we do this in two stages.  Stage one asynchronously opens the
+	 * destination file for writing.  Stage two spawns a thread that
+	 * decodes the MIME part to the destination file.  This stage is
+	 * not cancellable, unfortunately. */
+	else if (CAMEL_IS_MIME_PART (mime_part)) {
+		g_object_set_data_full (
+			G_OBJECT (file_activity),
+			"attachment", g_object_ref (attachment),
+			(GDestroyNotify) g_object_unref);
+		g_file_replace_async (
+			destination, NULL, FALSE,
+			G_FILE_CREATE_REPLACE_DESTINATION,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_save_part_cb,
+			g_object_ref (file_activity));
+	}
 }
 
-const gchar *
-e_attachment_get_filename (EAttachment *attachment)
+#if 0
+typedef struct {
+	gint io_priority;
+	GCancellable *cancellable;
+	GSimpleAsyncResult *simple;
+	GFileInfo *file_info;
+} BuildMimePartData;
+
+static BuildMimePartData *
+attachment_build_mime_part_data_new (EAttachment *attachment,
+                                     gint io_priority,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data,
+                                     gpointer source_tag)
+{
+	BuildMimePartData *data;
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (attachment), callback, user_data, source_tag);
+
+	if (G_IS_CANCELLABLE (cancellable))
+		g_object_ref (cancellable);
+
+	data = g_slice_new0 (BuildMimePartData);
+	data->io_priority = io_priority;
+	data->cancellable = cancellable;
+	data->simple = simple;
+	return data;
+}
+
+static void
+attachment_build_mime_part_data_free (BuildMimePartData *data)
 {
-	CamelMimePart *mime_part;
-	const gchar *filename;
+	if (data->attachment != NULL)
+		g_object_unref (data->attachment);
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	if (data->cancellable != NULL)
+		g_object_unref (data->cancellable);
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		filename = camel_mime_part_get_filename (mime_part);
-	else
-		filename = attachment->priv->filename;
+	if (data->simple != NULL)
+		g_object_unref (data->simple);
 
-	return filename;
+	if (data->file_info != NULL)
+		g_object_unref (data->file_info);
+
+	g_slice_free (BuildMimePartData, data);
 }
 
-void
-e_attachment_set_filename (EAttachment *attachment,
-                           const gchar *filename)
+static void
+attachment_build_mime_part_splice_cb (GObject *source,
+                                      GAsyncResult *result,
+                                      gpointer user_data)
 {
+	GSimpleAsyncResult *final_result;
+	GCancellable *cancellable;
+	EAttachment *attachment;
+	CamelDataWrapper *wrapper;
 	CamelMimePart *mime_part;
+	CamelStream *stream;
+	const gchar *content_type;
+	gchar *mime_type;
+	gssize length;
+	gpointer data;
+	GError *error = NULL;
 
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	final_result = G_SIMPLE_ASYNC_RESULT (user_data);
 
-	g_free (attachment->priv->filename);
-	attachment->priv->filename = g_strdup (filename);
+	cancellable = g_cancellable_get_current ();
+	g_cancellable_pop_current (cancellable);
+	g_object_unref (cancellable);
+
+	length = g_output_stream_splice_finish (
+		G_OUTPUT_STREAM (source), result, &error);
+	if (error != NULL)
+		goto fail;
+
+	data = g_memory_output_stream_get_data (
+		G_MEMORY_OUTPUT_STREAM (source));
+
+	attachment = E_ATTACHMENT (
+		g_async_result_get_source_object (
+		G_ASYNC_RESULT (final_result)));
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part != NULL)
-		camel_mime_part_set_filename (mime_part, filename);
+	if (e_attachment_is_rfc822 (attachment))
+		wrapper = (CamelDataWrapper *) camel_mime_message_new ();
+	else
+		wrapper = camel_data_wrapper_new ();
 
-	g_object_notify (G_OBJECT (attachment), "filename");
-}
+	content_type = e_attachment_get_content_type (attachment);
+	mime_type = g_content_type_get_mime_type (content_type);
 
-CamelMimePart *
-e_attachment_get_mime_part (EAttachment *attachment)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	stream = camel_stream_mem_new_with_buffer (data, length);
+	camel_data_wrapper_construct_from_stream (wrapper, stream);
+	camel_data_wrapper_set_mime_type (wrapper, mime_type);
+	camel_object_unref (stream);
 
-	return attachment->priv->mime_part;
-}
+	mime_part = camel_mime_part_new ();
+	camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
 
-const gchar *
-e_attachment_get_mime_type (EAttachment *attachment)
-{
-	CamelContentType *content_type;
-	CamelMimePart *mime_part;
-	const gchar *filename;
-	gchar *mime_type;
+	g_simple_async_result_set_op_res_gpointer (
+		final_result, mime_part, camel_object_unref);
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	g_simple_async_result_complete (final_result);
 
-	if (attachment->priv->mime_type != NULL)
-		goto exit;
+	camel_object_unref (wrapper);
+	g_free (mime_type);
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	filename = e_attachment_get_filename (attachment);
-	content_type = camel_mime_part_get_content_type (mime_part);
+	return;
 
-	if (mime_part == NULL)
-		mime_type = attachment_guess_mime_type (filename);
-	else {
-		content_type = camel_mime_part_get_content_type (mime_part);
-		mime_type = camel_content_type_simple (content_type);
-	}
+fail:
+	g_simple_async_result_set_from_error (final_result, error);
+	g_simple_async_result_complete (final_result);
+	g_error_free (error);
+}
 
-	attachment->priv->mime_type = mime_type;
+static void
+attachment_build_mime_part_read_cb (GObject *source,
+                                    GAsyncResult *result,
+                                    BuildMimePartData *data)
+{
+	GFileInputStream *input_stream;
+	GOutputStream *output_stream;
+	GCancellable *cancellable;
+	GError *error = NULL;
 
-exit:
-	return attachment->priv->mime_type;
+	input_stream = g_file_read_finish (G_FILE (source), result, &error);
+	if (error != NULL)
+		goto fail;
+
+	output_stream = g_memory_output_stream_new (
+		NULL, 0, g_realloc, g_free);
+
+	g_output_stream_splice_async (
+		output_stream, G_INPUT_STREAM (input_stream),
+		G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+		G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+		G_PRIORITY_DEFAULT, cancellable,
+		attachment_build_mime_part_splice_cb, result);
+
+	g_cancellable_push_current (cancellable);
+
+	g_object_unref (input_stream);
+	g_object_unref (output_stream);
+
+	return;
+
+fail:
+	g_simple_async_result_set_from_error (final_result, error);
+	g_simple_async_result_complete (final_result);
+	g_error_free (error);
 }
 
-GdkPixbuf *
-e_attachment_get_thumbnail (EAttachment *attachment)
+static gboolean
+attachment_build_mime_part_idle_cb (BuildMimePartData *data)
 {
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	GObject *source;
+	GAsyncResult *result;
+	GFileInfo *file_info;
+	GFile *file;
+	GError *error = NULL;
+
+	if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
+		goto cancelled;
+
+	result = G_ASYNC_RESULT (data->simple);
+	source = g_async_result_get_source_object (result);
+	file_info = e_attachment_get_file_info (E_ATTACHMENT (source));
+
+	/* Poll again on the next idle. */
+	if (!G_IS_FILE_INFO (file_info))
+		return TRUE;
+
+	/* We have a GFileInfo, so on to step 2. */
+
+	data->file_info = g_file_info_dup (file_info);
+	file = e_attachment_get_file (E_ATTACHMENT (source));
+
+	/* Because Camel's stream API is synchronous and not
+	 * cancellable, we have to asynchronously read the file
+	 * into memory and then encode it to a MIME part.  That
+	 * means double buffering the file contents in memory,
+	 * unfortunately. */
+	g_file_read_async (
+		file, data->io_priority, data->cancellable,
+		attachment_build_mime_part_read_cb, data);
+
+	return FALSE;
+
+cancelled:
+	g_simple_async_result_set_op_res_gboolean (data->simple, FALSE);
+	g_simple_async_result_set_from_error (data->simple, error);
+	g_simple_async_result_complete (data->simple);
 
-	return attachment->priv->thumbnail;
+	build_mime_part_data_free (data);
+	g_error_free (error);
+
+	return FALSE;
 }
 
 void
-e_attachment_set_thumbnail (EAttachment *attachment,
-                            GdkPixbuf *thumbnail)
+e_attachment_build_mime_part_async (EAttachment *attachment,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
 {
+	CamelMimePart *mime_part;
+	GSimpleAsyncResult *result;
+	GFile *file;
+
 	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (callback != NULL);
 
-	if (thumbnail != NULL) {
-		g_return_if_fail (GDK_IS_PIXBUF (thumbnail));
-		g_object_ref (thumbnail);
+	file = e_attachment_get_file (attachment);
+	mime_part = e_attachment_get_mime_part (attachment);
+	g_return_if_fail (file != NULL || mime_part != NULL);
+
+	result = g_simple_async_result_new (
+		G_OBJECT (attachment), callback, user_data,
+		e_attachment_build_mime_part_async);
+
+	/* First try the easy way out. */
+	if (CAMEL_IS_MIME_PART (mime_part)) {
+		camel_object_ref (mime_part);
+		g_simple_async_result_set_op_res_gpointer (
+			result, mime_part, camel_object_unref);
+		g_simple_async_result_complete_in_idle (result);
+		return;
 	}
 
-	if (attachment->priv->thumbnail != NULL)
-		g_object_unref (attachment->priv->thumbnail);
+	/* XXX g_cancellable_push_current() documentation lies.
+	 *     The function rejects NULL pointers, so create a
+	 *     dummy GCancellable if necessary. */
+	if (cancellable == NULL)
+		cancellable = g_cancellable_new ();
+	else
+		g_object_ref (cancellable);
 
-	attachment->priv->thumbnail = thumbnail;
+	/* Because Camel's stream API is synchronous and not
+	 * cancellable, we have to asynchronously read the file
+	 * into memory and then encode it to a MIME part.  That
+	 * means it's double buffered, unfortunately. */
+	g_file_read_async (
+		file, G_PRIORITY_DEFAULT, cancellable,
+		attachment_build_mime_part_read_cb, result);
 
-	g_object_notify (G_OBJECT (attachment), "thumbnail");
+	g_cancellable_push_current (cancellable);
 }
 
-gboolean
-e_attachment_is_image (EAttachment *attachment)
+CamelMimePart *
+e_attachment_build_mime_part_finish (EAttachment *attachment,
+                                     GAsyncResult *result,
+                                     GError **error)
 {
-	CamelContentType *content_type;
 	CamelMimePart *mime_part;
+	GSimpleAsyncResult *simple_result;
+	gboolean async_result_is_valid;
+	gpointer source_tag;
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
 
-	mime_part = e_attachment_get_mime_part (attachment);
-	if (mime_part == NULL)
-		return FALSE;
+	source_tag = e_attachment_build_mime_part_async;
+	async_result_is_valid = g_simple_async_result_is_valid (
+		result, G_OBJECT (attachment), source_tag);
+	g_return_val_if_fail (async_result_is_valid, NULL);
 
-	content_type = camel_mime_part_get_content_type (mime_part);
+	simple_result = G_SIMPLE_ASYNC_RESULT (result);
+	g_simple_async_result_propagate_error (simple_result, error);
+	mime_part = g_simple_async_result_get_op_res_gpointer (simple_result);
+	attachment_file_info_to_mime_part (attachment, mime_part);
 
-	return camel_content_type_is (content_type, "image", "*");
-}
+	if (CAMEL_IS_MIME_PART (mime_part))
+		camel_object_ref (mime_part);
 
-gboolean
-e_attachment_is_inline (EAttachment *attachment)
-{
-	const gchar *disposition;
+	g_object_unref (result);
 
-	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+	return mime_part;
+}
+#endif
 
-	disposition = e_attachment_get_disposition (attachment);
-	g_return_val_if_fail (disposition != NULL, FALSE);
+void
+_e_attachment_set_reference (EAttachment *attachment,
+                             GtkTreeRowReference *reference)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (reference != NULL);
 
-	return (g_ascii_strcasecmp (disposition, "inline") == 0);
+	gtk_tree_row_reference_free (attachment->priv->reference);
+	attachment->priv->reference = gtk_tree_row_reference_copy (reference);
 }

Modified: branches/kill-bonobo/widgets/misc/e-attachment.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment.h	Fri Mar 20 19:06:59 2009
@@ -1,4 +1,6 @@
 /*
+ * e-attachment.h
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -13,10 +15,6 @@
  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
  *
  *
- * Authors:
- *		Ettore Perazzoli <ettore ximian com>
- *		Srinivasa Ragavan <sragavan novell com>
- *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
@@ -25,11 +23,10 @@
 #define E_ATTACHMENT_H
 
 #include <gio/gio.h>
-#include <gtk/gtk.h>
-#include <glade/glade-xml.h>
 #include <camel/camel-mime-part.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-cipher-context.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+#include <widgets/misc/e-file-activity.h>
 
 /* Standard GObject macros */
 #define E_TYPE_ATTACHMENT \
@@ -45,7 +42,7 @@
 	((obj), E_TYPE_ATTACHMENT))
 #define E_IS_ATTACHMENT_CLASS(cls) \
 	(G_TYPE_CHECK_CLASS_TYPE \
-	((obj), E_TYPE_ATTACHMENT))
+	((cls), E_TYPE_ATTACHMENT))
 #define E_ATTACHMENT_GET_CLASS(obj) \
 	(G_TYPE_INSTANCE_GET_CLASS \
 	((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
@@ -58,63 +55,58 @@
 
 struct _EAttachment {
 	GObject parent;
-
-	gboolean guessed_type;
-	gulong size;
-
-	GCancellable *cancellable;
-
-	gboolean is_available_local;
-	int percentage;
-	int index;
-	char *store_uri;
-
-	/* Status of signed/encrypted attachments */
-	camel_cipher_validity_sign_t sign;
-	camel_cipher_validity_encrypt_t encrypt;
-
 	EAttachmentPrivate *priv;
 };
 
 struct _EAttachmentClass {
 	GObjectClass parent_class;
-
-	void		(*changed)		(EAttachment *attachment);
-	void		(*update)		(EAttachment *attachment,
-						 gchar *message);
 };
 
 GType		e_attachment_get_type		(void);
-EAttachment *	e_attachment_new		(const gchar *filename,
-						 const gchar *disposition,
-						 CamelException *ex);
-EAttachment *	e_attachment_new_remote_file	(GtkWindow *error_dlg_parent,
-						 const gchar *url,
-						 const gchar *disposition,
-						 const gchar *path,
-						 CamelException *ex);
-void		e_attachment_build_remote_file	(const gchar *filename,
-						 EAttachment *attachment,
-						 CamelException *ex);
-EAttachment *	e_attachment_new_from_mime_part	(CamelMimePart *part);
-void		e_attachment_edit		(EAttachment *attachment,
-						 GtkWindow *parent);
-const gchar *	e_attachment_get_description	(EAttachment *attachment);
-void		e_attachment_set_description	(EAttachment *attachment,
-						 const gchar *description);
+EAttachment *	e_attachment_new		(void);
+EAttachment *	e_attachment_new_for_path	(const gchar *path);
+EAttachment *	e_attachment_new_for_uri	(const gchar *uri);
+EAttachment *	e_attachment_new_for_message	(CamelMimeMessage *message);
+void		e_attachment_add_to_multipart	(EAttachment *attachment,
+						 CamelMultipart *multipart,
+						 const gchar *default_charset);
 const gchar *	e_attachment_get_disposition	(EAttachment *attachment);
 void		e_attachment_set_disposition	(EAttachment *attachment,
 						 const gchar *disposition);
-const gchar *	e_attachment_get_filename	(EAttachment *attachment);
-void		e_attachment_set_filename	(EAttachment *attachment,
-						 const gchar *filename);
+GFile *		e_attachment_get_file		(EAttachment *attachment);
+void		e_attachment_set_file		(EAttachment *attachment,
+						 GFile *file);
+GFileInfo *	e_attachment_get_file_info	(EAttachment *attachment);
 CamelMimePart *	e_attachment_get_mime_part	(EAttachment *attachment);
-const gchar *	e_attachment_get_mime_type	(EAttachment *attachment);
-GdkPixbuf *	e_attachment_get_thumbnail	(EAttachment *attachment);
-void		e_attachment_set_thumbnail	(EAttachment *attachment,
-						 GdkPixbuf *pixbuf);
+void		e_attachment_set_mime_part	(EAttachment *attachment,
+						 CamelMimePart *mime_part);
+const gchar *	e_attachment_get_content_type	(EAttachment *attachment);
+const gchar *	e_attachment_get_display_name	(EAttachment *attachment);
+const gchar *	e_attachment_get_description	(EAttachment *attachment);
+GIcon *		e_attachment_get_icon		(EAttachment *attachment);
+const gchar *	e_attachment_get_thumbnail_path	(EAttachment *attachment);
+guint64		e_attachment_get_size		(EAttachment *attachment);
 gboolean	e_attachment_is_image		(EAttachment *attachment);
-gboolean	e_attachment_is_inline		(EAttachment *attachment);
+gboolean	e_attachment_is_rfc822		(EAttachment *attachment);
+void		e_attachment_save_async		(EAttachment *attachment,
+						 EFileActivity *file_activity,
+						 GFile *destination);
+
+#if 0
+void		e_attachment_build_mime_part_async
+						(EAttachment *attachment,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelMimePart *	e_attachment_build_mime_part_finish
+						(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GError **error);
+#endif
+
+/* For use by EAttachmentStore only. */
+void		_e_attachment_set_reference	(EAttachment *attachment,
+						 GtkTreeRowReference *reference);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/widgets/misc/e-file-activity.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-file-activity.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-file-activity.c	Fri Mar 20 19:06:59 2009
@@ -21,18 +21,25 @@
 
 #include "e-file-activity.h"
 
+#include <stdarg.h>
+
 #define E_FILE_ACTIVITY_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_FILE_ACTIVITY, EFileActivityPrivate))
 
 struct _EFileActivityPrivate {
 	GCancellable *cancellable;
+	GAsyncResult *result;
+	GFile *file;
+
 	gulong handler_id;
 };
 
 enum {
 	PROP_0,
-	PROP_CANCELLABLE
+	PROP_CANCELLABLE,
+	PROP_FILE,
+	PROP_RESULT
 };
 
 static gpointer parent_class;
@@ -49,6 +56,18 @@
 				E_FILE_ACTIVITY (object),
 				g_value_get_object (value));
 			return;
+
+		case PROP_FILE:
+			e_file_activity_set_file (
+				E_FILE_ACTIVITY (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_RESULT:
+			e_file_activity_set_result (
+				E_FILE_ACTIVITY (object),
+				g_value_get_object (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -66,6 +85,18 @@
 				value, e_file_activity_get_cancellable (
 				E_FILE_ACTIVITY (object)));
 			return;
+
+		case PROP_FILE:
+			g_value_set_object (
+				value, e_file_activity_get_file (
+				E_FILE_ACTIVITY (object)));
+			return;
+
+		case PROP_RESULT:
+			g_value_set_object (
+				value, e_file_activity_get_result (
+				E_FILE_ACTIVITY (object)));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -85,6 +116,16 @@
 		priv->cancellable = NULL;
 	}
 
+	if (priv->result != NULL) {
+		g_object_unref (priv->result);
+		priv->result = NULL;
+	}
+
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -129,6 +170,26 @@
 			NULL,
 			G_TYPE_CANCELLABLE,
 			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILE,
+		g_param_spec_object (
+			"file",
+			"File",
+			NULL,
+			G_TYPE_FILE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_RESULT,
+		g_param_spec_object (
+			"result",
+			"Result",
+			NULL,
+			G_TYPE_ASYNC_RESULT,
+			G_PARAM_READWRITE));
 }
 
 static void
@@ -179,6 +240,22 @@
 		"primary-text", primary_text, NULL);
 }
 
+EActivity *
+e_file_activity_newv (const gchar *format, ...)
+{
+	EActivity *activity;
+	gchar *primary_text;
+	va_list args;
+
+	va_start (args, format);
+	primary_text = g_strdup_vprintf (format, args);
+	activity = e_file_activity_new (primary_text);
+	g_free (primary_text);
+	va_end (args);
+
+	return activity;
+}
+
 GCancellable *
 e_file_activity_get_cancellable (EFileActivity *file_activity)
 {
@@ -218,6 +295,60 @@
 	g_object_notify (G_OBJECT (file_activity), "cancellable");
 }
 
+GFile *
+e_file_activity_get_file (EFileActivity *file_activity)
+{
+	g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+	return file_activity->priv->file;
+}
+
+void
+e_file_activity_set_file (EFileActivity *file_activity,
+                          GFile *file)
+{
+	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+	if (file != NULL) {
+		g_return_if_fail (G_IS_FILE (file));
+		g_object_ref (file);
+	}
+
+	if (file_activity->priv->file != NULL)
+		g_object_unref (file_activity->priv->file);
+
+	file_activity->priv->file = file;
+
+	g_object_notify (G_OBJECT (file_activity), "file");
+}
+
+GAsyncResult *
+e_file_activity_get_result (EFileActivity *file_activity)
+{
+	g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+	return file_activity->priv->result;
+}
+
+void
+e_file_activity_set_result (EFileActivity *file_activity,
+                            GAsyncResult *result)
+{
+	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+	if (result != NULL) {
+		g_return_if_fail (G_IS_ASYNC_RESULT (result));
+		g_object_ref (result);
+	}
+
+	if (file_activity->priv->result != NULL)
+		g_object_unref (file_activity->priv->result);
+
+	file_activity->priv->result = result;
+
+	g_object_notify (G_OBJECT (file_activity), "result");
+}
+
 void
 e_file_activity_progress (goffset current_num_bytes,
                           goffset total_num_bytes,

Modified: branches/kill-bonobo/widgets/misc/e-file-activity.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-file-activity.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-file-activity.h	Fri Mar 20 19:06:59 2009
@@ -23,7 +23,7 @@
 #define E_FILE_ACTIVITY_H
 
 #include <gio/gio.h>
-#include <e-activity.h>
+#include <widgets/misc/e-activity.h>
 
 /* Standard GObject macros */
 #define E_TYPE_FILE_ACTIVITY \
@@ -61,9 +61,17 @@
 
 GType		e_file_activity_get_type	(void);
 EActivity *	e_file_activity_new		(const gchar *primary_text);
+EActivity *	e_file_activity_newv		(const gchar *format,
+						 ...) G_GNUC_PRINTF (1, 2);
 GCancellable *	e_file_activity_get_cancellable	(EFileActivity *file_activity);
 void		e_file_activity_set_cancellable (EFileActivity *file_activity,
 						 GCancellable *cancellable);
+GFile *		e_file_activity_get_file	(EFileActivity *file_activity);
+void		e_file_activity_set_file	(EFileActivity *file_activity,
+						 GFile *file);
+GAsyncResult *	e_file_activity_get_result	(EFileActivity *file_activity);
+void		e_file_activity_set_result	(EFileActivity *file_activity,
+						 GAsyncResult *result);
 
 /* This can be used as a GFileProgressCallback. */
 void		e_file_activity_progress	(goffset current_num_bytes,

Modified: branches/kill-bonobo/widgets/misc/e-timeout-activity.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-timeout-activity.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-timeout-activity.c	Fri Mar 20 19:06:59 2009
@@ -21,6 +21,8 @@
 
 #include "e-timeout-activity.h"
 
+#include <stdarg.h>
+
 #define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
@@ -166,6 +168,22 @@
 		"primary-text", primary_text, NULL);
 }
 
+EActivity *
+e_timeout_activity_newv (const gchar *format, ...)
+{
+	EActivity *activity;
+	gchar *primary_text;
+	va_list args;
+
+	va_start (args, format);
+	primary_text = g_strdup_vprintf (format, args);
+	activity = e_timeout_activity_new (primary_text);
+	g_free (primary_text);
+	va_end (args);
+
+	return activity;
+}
+
 void
 e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
                                 guint seconds)

Modified: branches/kill-bonobo/widgets/misc/e-timeout-activity.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-timeout-activity.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-timeout-activity.h	Fri Mar 20 19:06:59 2009
@@ -63,6 +63,8 @@
 
 GType		e_timeout_activity_get_type	(void);
 EActivity *	e_timeout_activity_new		(const gchar *primary_text);
+EActivity *	e_timeout_activity_newv		(const gchar *format,
+						 ...) G_GNUC_PRINTF (1, 2);
 void		e_timeout_activity_set_timeout	(ETimeoutActivity *timeout_activity,
 						 guint seconds);
 

Modified: branches/kill-bonobo/widgets/table/Makefile.am
==============================================================================
--- branches/kill-bonobo/widgets/table/Makefile.am	(original)
+++ branches/kill-bonobo/widgets/table/Makefile.am	Fri Mar 20 19:06:59 2009
@@ -9,8 +9,9 @@
 	e-table-field-chooser.glade
 
 INCLUDES =					\
-	-I$(top_srcdir)                         \
-	-I$(top_srcdir)/widgets                 \
+	-I$(top_srcdir)				\
+	-I$(top_srcdir)/widgets			\
+	$(E_UTIL_CFLAGS)			\
 	$(E_WIDGETS_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)		\
 	-DEVOLUTION_GLADEDIR=\"$(gladedir)\"	\
@@ -147,6 +148,7 @@
 	$(WIN32_BOOTSTRAP_LIBS)				\
 	$(top_builddir)/e-util/libeutil.la		\
 	$(top_builddir)/a11y/libevolution-a11y.la	\
+	$(E_UTIL_LIBS)					\
 	$(E_WIDGETS_LIBS)				\
 	$(GNOME_PLATFORM_LIBS)
 

Modified: branches/kill-bonobo/widgets/text/Makefile.am
==============================================================================
--- branches/kill-bonobo/widgets/text/Makefile.am	(original)
+++ branches/kill-bonobo/widgets/text/Makefile.am	Fri Mar 20 19:06:59 2009
@@ -5,6 +5,7 @@
 INCLUDES =					\
 	-I$(top_srcdir)				\
 	-I$(top_srcdir)/widgets			\
+	$(E_UTIL_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)		\
 	-DG_LOG_DOMAIN=\"e-text\"
 
@@ -30,5 +31,6 @@
 	$(top_builddir)/e-util/libeutil.la		\
 	$(top_builddir)/a11y/libevolution-a11y.la	\
 	$(top_builddir)/widgets/table/libetable.la	\
+	$(E_UTIL_LIBS)					\
 	$(GNOME_PLATFORM_LIBS)				\
 	$(REGEX_LIBS)



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