evolution r37389 - in branches/kill-bonobo: . calendar/gui calendar/gui/dialogs composer e-util mail plugins/attachment-reminder shell widgets/misc



Author: mbarnes
Date: Mon Mar  9 03:31:24 2009
New Revision: 37389
URL: http://svn.gnome.org/viewvc/evolution?rev=37389&view=rev

Log:
Cleaning up the attachment bar, centralizing its popup menu, and converting
everything to GtkUIManager/GtkActions.  Saving progress mid-stream... not
sure about the MIME part utilities yet.

Also, add some EActivity subclasses.  Considering an EFileActivity subclass
for asynchronous GIO operations (loading/saving attachments, etc.), but still
ironing out details.


Added:
   branches/kill-bonobo/widgets/misc/e-alert-activity.c
   branches/kill-bonobo/widgets/misc/e-alert-activity.h
   branches/kill-bonobo/widgets/misc/e-attachment-dialog.c
   branches/kill-bonobo/widgets/misc/e-attachment-dialog.h
   branches/kill-bonobo/widgets/misc/e-mime-part-utils.c
   branches/kill-bonobo/widgets/misc/e-mime-part-utils.h
   branches/kill-bonobo/widgets/misc/e-timeout-activity.c
   branches/kill-bonobo/widgets/misc/e-timeout-activity.h
Modified:
   branches/kill-bonobo/calendar/gui/dialogs/comp-editor.c
   branches/kill-bonobo/calendar/gui/e-cal-popup.c
   branches/kill-bonobo/composer/e-composer-private.c
   branches/kill-bonobo/composer/e-msg-composer.c
   branches/kill-bonobo/configure.in
   branches/kill-bonobo/e-util/e-binding.c
   branches/kill-bonobo/e-util/e-util.c
   branches/kill-bonobo/e-util/e-util.h
   branches/kill-bonobo/mail/em-composer-prefs.c
   branches/kill-bonobo/mail/em-folder-view.c
   branches/kill-bonobo/mail/em-format-html-display.c
   branches/kill-bonobo/mail/em-popup.c
   branches/kill-bonobo/mail/em-utils.c
   branches/kill-bonobo/mail/mail-mt.c
   branches/kill-bonobo/plugins/attachment-reminder/Makefile.am
   branches/kill-bonobo/shell/e-shell-window.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-bar.h
   branches/kill-bonobo/widgets/misc/e-attachment.c
   branches/kill-bonobo/widgets/misc/e-attachment.h

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	Mon Mar  9 03:31:24 2009
@@ -180,7 +180,6 @@
 
 static void obj_modified_cb (ECal *client, GList *objs, CompEditor *editor);
 static void obj_removed_cb (ECal *client, GList *uids, CompEditor *editor);
-static gboolean open_attachment (EAttachmentBar *bar, CompEditor *editor);
 
 G_DEFINE_TYPE (CompEditor, comp_editor, GTK_TYPE_WINDOW)
 
@@ -1801,7 +1800,7 @@
  	priv->warned = FALSE;
 	priv->is_group_item = FALSE;
 
-	priv->attachment_bar = e_attachment_bar_new (NULL);
+	priv->attachment_bar = e_attachment_bar_new ();
 	priv->manager = gtk_ui_manager_new ();
 
         gtk_window_add_accel_group (
@@ -1988,233 +1987,9 @@
 						  _("Show Attachment _Bar"));
 }
 
-static gboolean
-open_attachment (EAttachmentBar *bar, CompEditor *editor)
-{
-	GnomeIconList *icon_list;
-	GList *p;
-	int num;
-	char *attach_file_url;
-
-	if (E_IS_ATTACHMENT_BAR (bar)) {
-		icon_list = GNOME_ICON_LIST (bar);
-		p = gnome_icon_list_get_selection (icon_list);
-		if (p) {
-			EAttachment *attachment;
-			GSList *list;
-			const char *comp_uid = NULL;
-			char *filename = NULL;
-			const char *local_store = e_cal_get_local_attachment_store (editor->priv->client);
-
-			e_cal_component_get_uid (editor->priv->comp, &comp_uid);
-			num = GPOINTER_TO_INT (p->data);
-			list = e_attachment_bar_get_attachment (bar, num);
-			attachment = list->data;
-			g_slist_free (list);
-
-			filename = g_strdup_printf ("%s-%s",
-						    comp_uid,
-						    camel_mime_part_get_filename(attachment->body));
-
-			attach_file_url = g_build_path ("/", local_store, filename, NULL);
-
-			/* launch the url now */
-			e_show_uri (GTK_WINDOW (editor), attach_file_url);
-
-			g_free (filename);
-			g_free (attach_file_url); }
-		return TRUE;
-	} else
-		return FALSE;
-}
-
-static	gboolean
-attachment_bar_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, CompEditor *editor)
-{
-	if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS)
-		if (open_attachment (bar, editor))
-				return TRUE;
-	return FALSE;
-}
-
-/* Callbacks.  */
-
-static void
-cab_open(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-	CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-
-	if (!open_attachment (bar, editor))
-		g_message ("\n Open failed");
-}
-
-static void
-cab_add(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-        CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-	GPtrArray *file_list;
-	gboolean is_inline = FALSE;
-	int i;
-
-	file_list = comp_editor_select_file_attachments (editor, &is_inline);
-	/*TODO add a good implementation here */
-	if (!file_list)
-		return;
-	for (i = 0; i < file_list->len; i++) {
-		CamelURL *url;
-
-		url = camel_url_new (file_list->pdata[i], NULL);
-		if (url == NULL)
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file"))
-			 e_attachment_bar_attach (bar, url->path, is_inline ? "inline" : "attachment");
-		else
-			 e_attachment_bar_attach_remote_file (bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
-		g_free (file_list->pdata[i]);
-		camel_url_free (url);
-	}
-
-	g_ptr_array_free (file_list, TRUE);
-}
-
-static void
-cab_properties(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-
-	e_attachment_bar_edit_selected(bar);
-}
-
-static void
-cab_remove(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-
-	e_attachment_bar_remove_selected(bar);
-}
-
-/* Popup menu handling.  */
-static EPopupItem cab_popups[] = {
-	{ E_POPUP_ITEM, "10.attach", N_("_Open"), cab_open, NULL, GTK_STOCK_OPEN, E_CAL_POPUP_ATTACHMENTS_ONE},
-	{ E_POPUP_ITEM, "20.attach", N_("_Remove"), cab_remove, NULL, GTK_STOCK_REMOVE, E_CAL_POPUP_ATTACHMENTS_MANY | E_CAL_POPUP_ATTACHMENTS_MODIFY },
-	{ E_POPUP_ITEM, "30.attach", N_("_Properties"), cab_properties, NULL, GTK_STOCK_PROPERTIES, E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_BAR, "40.attach.00", NULL, NULL, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_MANY|E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "40.attach.01", N_("_Add attachment..."), cab_add, NULL, GTK_STOCK_ADD, E_CAL_POPUP_ATTACHMENTS_MODIFY},
-};
-
-static void
-cab_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;
-}
-
-static void
-cab_popups_free(EPopup *ep, GSList *l, void *data)
-{
-	g_slist_free(l);
-}
-
-/* if id != -1, then use it as an index for target of the popup */
-static void
-cab_popup(EAttachmentBar *bar, GdkEventButton *event, int id)
-{
-	GSList *attachments = NULL, *menus = NULL;
-	int i;
-	ECalPopup *ecp;
-	ECalPopupTargetAttachments *t;
-	GtkMenu *menu;
-	CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-
-        attachments = e_attachment_bar_get_attachment(bar, id);
-
-	for (i=0;i<sizeof(cab_popups)/sizeof(cab_popups[0]);i++)
-		menus = g_slist_prepend(menus, &cab_popups[i]);
-
-	/** @HookPoint-ECalPopup: Calendar Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.calendar.attachmentbar.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: ECalPopupTargetAttachments
-	 *
-	 * This is the context menu on the calendar attachment bar.
-	 */
-	ecp = e_cal_popup_new("org.gnome.evolution.calendar.attachmentbar.popup");
-	e_popup_add_items((EPopup *)ecp, menus, NULL, cab_popups_free, bar);
-	t = e_cal_popup_target_new_attachments(ecp, editor, attachments);
-	t->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once((EPopup *)ecp, (EPopupTarget *)t, 0);
-
-	if (event == NULL)
-		gtk_menu_popup(menu, NULL, NULL, cab_popup_position, bar, 0, gtk_get_current_event_time());
-	else
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
-}
 
 /* GtkWidget methods.  */
 
-static gboolean
-popup_menu_event (EAttachmentBar *bar)
-{
-	cab_popup (bar, NULL, -1);
-
-	return TRUE;
-}
-
-
-static int
-button_press_event (EAttachmentBar *bar,
-                    GdkEventButton *event)
-{
-	GnomeIconList *icon_list = GNOME_ICON_LIST (bar);
-	int icon_number = -1;
-
-	if (event->button != 3)
-		return FALSE;
-
-	if (!gnome_icon_list_get_selection (icon_list)) {
-		icon_number = gnome_icon_list_get_icon_at (icon_list, event->x, event->y);
-		if (icon_number >= 0) {
-			gnome_icon_list_unselect_all(icon_list);
-			gnome_icon_list_select_icon (icon_list, icon_number);
-		}
-	}
-
-	cab_popup(bar, event, icon_number);
-
-	return TRUE;
-}
-
-static gint
-key_press_event (EAttachmentBar *bar,
-                 GdkEventKey *event)
-{
-	if (event->keyval == GDK_Delete) {
-                e_attachment_bar_remove_selected (bar);
-                return TRUE;
-        }
-
-        return FALSE;
-}
-
 static gint
 editor_key_press_event (CompEditor *editor,
                         GdkEventKey *event)
@@ -2275,18 +2050,12 @@
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
 					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
-	g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK (button_press_event), NULL);
-        g_signal_connect (priv->attachment_bar, "key_press_event", G_CALLBACK (key_press_event), NULL);
-        g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK (popup_menu_event), NULL);
-
 	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);
-	g_signal_connect (GNOME_ICON_LIST (priv->attachment_bar), "event",
-			  G_CALLBACK (attachment_bar_icon_clicked_cb), editor);
 	priv->attachment_expander_label =
 		gtk_label_new_with_mnemonic (_("Show Attachment _Bar"));
 	priv->attachment_expander_num = gtk_label_new ("");

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	Mon Mar  9 03:31:24 2009
@@ -167,11 +167,13 @@
 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;
 
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body;
+	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 */
@@ -201,7 +203,11 @@
 	parts = ((ECalPopupTargetAttachments *) t)->attachments;
 
 	for (;parts; parts=parts->next) {
-		path = temp_save_part (((EAttachment *)parts->data)->body, dir, FALSE);
+		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);
 	}
@@ -210,13 +216,15 @@
 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 = NULL;
+	CamelMimePart *part;
 
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body;
+	attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) t)->attachments->data);
+	part = e_attachment_get_mime_part (attachment);
 
 	if (!part)
 		return;
@@ -293,10 +301,12 @@
 ecalp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
 {
 	char *path;
+	EAttachment *attachment;
 	EPopupTarget *target = ep->target;
 	CamelMimePart *part;
 
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) target)->attachments->data)->body;
+	attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) target)->attachments->data);
+	part = e_attachment_get_mime_part (attachment);
 
 	path = temp_save_part(part, NULL, FALSE);
 	if (path) {
@@ -370,6 +380,7 @@
 		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);
@@ -380,8 +391,9 @@
 
 		/* Only one attachment selected */
 		attachment = list->data;
-		mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body);
-		filename = camel_mime_part_get_filename(attachment->body);
+		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; }
@@ -788,7 +800,15 @@
 		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MANY;
 
 	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
-		if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*"))
+		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;
 	}

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	Mon Mar  9 03:31:24 2009
@@ -167,7 +167,7 @@
 	gtk_widget_show (widget);
 	container = widget;
 
-	widget = e_attachment_bar_new (NULL);
+	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);

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	Mon Mar  9 03:31:24 2009
@@ -974,107 +974,6 @@
 	return NULL;
 }
 
-/* Attachment Bar */
-
-static void
-emcab_add (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	GtkWidget *widget = data;
-	GtkWidget *composer;
-
-	composer = gtk_widget_get_toplevel (widget);
-	gtk_action_activate (ACTION (ATTACH));
-}
-
-static void
-emcab_properties (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	EAttachmentBar *attachment_bar = data;
-
-	e_attachment_bar_edit_selected (attachment_bar);
-}
-
-static void
-emcab_remove (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	EAttachmentBar *attachment_bar = data;
-
-	e_attachment_bar_remove_selected (attachment_bar);
-}
-
-static void
-emcab_popup_position (GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
-	GtkWidget *widget = user_data;
-	GnomeIconList *icon_list = user_data;
-	GList *selection;
-	GnomeCanvasPixbuf *image;
-
-	gdk_window_get_origin (widget->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;
-}
-
-static void
-emcab_popups_free (EPopup *ep, GSList *list, gpointer data)
-{
-	g_slist_free (list);
-}
-
-/* Popup menu handling.  */
-static EPopupItem emcab_popups[] = {
-	{ E_POPUP_ITEM, "10.attach", N_("_Remove"), emcab_remove, NULL, GTK_STOCK_REMOVE, EM_POPUP_ATTACHMENTS_MANY },
-	{ E_POPUP_ITEM, "20.attach", N_("_Properties"), emcab_properties, NULL, GTK_STOCK_PROPERTIES, EM_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_BAR, "30.attach.00", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MANY|EM_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "30.attach.01", N_("_Add attachment..."), emcab_add, NULL, GTK_STOCK_ADD, 0 },
-};
-
-/* if id != -1, then use it as an index for target of the popup */
-
-static void
-emcab_popup (EAttachmentBar *bar, GdkEventButton *event, int id)
-{
-	GSList *attachments = NULL, *menus = NULL;
-	int i;
-	EMPopup *emp;
-	EMPopupTargetAttachments *t;
-	GtkMenu *menu;
-
-	attachments = e_attachment_bar_get_attachment (bar, id);
-
-	for (i=0;i<sizeof (emcab_popups)/sizeof (emcab_popups[0]);i++)
-		menus = g_slist_prepend (menus, &emcab_popups[i]);
-
-	/** @HookPoint-EMPopup: Composer Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.mail.composer.attachmentbar.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: EMPopupTargetAttachments
-	 *
-	 * This is the context menu on the composer attachment bar.
-	 */
-	emp = em_popup_new ("org.gnome.evolution.mail.composer.attachmentbar.popup");
-	e_popup_add_items ((EPopup *)emp, menus, NULL, emcab_popups_free, bar);
-	t = em_popup_target_new_attachments (emp, attachments);
-	t->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once ((EPopup *)emp, (EPopupTarget *)t, 0);
-
-	if (event == NULL)
-		gtk_menu_popup (menu, NULL, NULL, emcab_popup_position, bar, 0, gtk_get_current_event_time ());
-	else
-		gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
-}
-
 /* Signatures */
 
 static gchar *
@@ -1352,29 +1251,6 @@
 
 /* Miscellaneous callbacks.  */
 
-static gint
-attachment_bar_button_press_event_cb (EAttachmentBar *attachment_bar,
-                                      GdkEventButton *event)
-{
-	GnomeIconList *icon_list;
-	gint icon_number;
-
-	if (event->button != 3)
-		return FALSE;
-
-	icon_list = GNOME_ICON_LIST (attachment_bar);
-	icon_number = gnome_icon_list_get_icon_at (
-		icon_list, event->x, event->y);
-	if (icon_number >= 0) {
-		gnome_icon_list_unselect_all (icon_list);
-		gnome_icon_list_select_icon (icon_list, icon_number);
-	}
-
-	emcab_popup (attachment_bar, event, icon_number);
-
-	return TRUE;
-}
-
 static void
 attachment_bar_changed_cb (EAttachmentBar *attachment_bar,
                            EMsgComposer *composer)
@@ -1415,26 +1291,6 @@
 	gtkhtml_editor_set_changed (editor, TRUE);
 }
 
-static gint
-attachment_bar_key_press_event_cb (EAttachmentBar *attachment_bar,
-                                   GdkEventKey *event)
-{
-	if (event->keyval == GDK_Delete) {
-		e_attachment_bar_remove_selected (attachment_bar);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static gboolean
-attachment_bar_popup_menu_cb (EAttachmentBar *attachment_bar)
-{
-	emcab_popup (attachment_bar, NULL, -1);
-
-	return TRUE;
-}
-
 static void
 attachment_expander_notify_cb (GtkExpander *expander,
                                GParamSpec *pspec,
@@ -2715,15 +2571,6 @@
 	/* Attachment Bar */
 
 	g_signal_connect (
-		composer->priv->attachment_bar, "button_press_event",
-		G_CALLBACK (attachment_bar_button_press_event_cb), NULL);
-	g_signal_connect (
-		composer->priv->attachment_bar, "key_press_event",
-		G_CALLBACK (attachment_bar_key_press_event_cb), NULL);
-	g_signal_connect (
-		composer->priv->attachment_bar, "popup-menu",
-		G_CALLBACK (attachment_bar_popup_menu_cb), NULL);
-	g_signal_connect (
 		composer->priv->attachment_bar, "changed",
 		G_CALLBACK (attachment_bar_changed_cb), composer);
 	g_signal_connect_after (

Modified: branches/kill-bonobo/configure.in
==============================================================================
--- branches/kill-bonobo/configure.in	(original)
+++ branches/kill-bonobo/configure.in	Mon Mar  9 03:31:24 2009
@@ -1790,11 +1790,10 @@
 all_plugins_experimental="$plugins_experimental_always ipod-sync tnef-attachments"
 
 dnl Temporary KILL-BONOBO hack
-enable_plugins="addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-attachments save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup"
+enable_plugins="attachment-reminder addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-attachments save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup"
 
 dnl PLUGINS NOT BUILDING YET
 dnl ------------------------
-dnl attachment-reminder
 dnl backup-restore
 dnl calendar-weather
 dnl default-mailer

Modified: branches/kill-bonobo/e-util/e-binding.c
==============================================================================
--- branches/kill-bonobo/e-util/e-binding.c	(original)
+++ branches/kill-bonobo/e-util/e-binding.c	Mon Mar  9 03:31:24 2009
@@ -524,11 +524,13 @@
 {
 	GdkColor color;
 	const gchar *string;
-	gboolean success;
+	gboolean success = FALSE;
 
 	string = g_value_get_string (src_value);
-	if (gdk_color_parse (string, &color))
+	if (gdk_color_parse (string, &color)) {
 		g_value_set_boxed (dst_value, &color);
+		success = TRUE;
+	}
 
 	return success;
 }

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	Mon Mar  9 03:31:24 2009
@@ -186,6 +186,33 @@
 }
 
 /**
+ * e_file_open_tmp:
+ * @name_used: location to store the actual named used, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Convenience function wraps g_file_open_tmp() but chooses a suitable
+ * filename template using both the package name and the user name.
+ *
+ * Returns: A file handle (as from open()) to the file opened for reading
+ *          and writing.  The file is opened in binary mode on platforms
+ *          where there is a difference.  The file handle should be closed
+ *          with close().  In case of errors, -1 is returned and @error
+ *          will be set.
+ **/
+gint
+e_file_open_tmp (gchar **name_used,
+                 GError **error)
+{
+	static gchar *template = NULL;
+
+	if (G_UNLIKELY (template == NULL))
+		template = g_strdup_printf (
+			PACKAGE "-%s-XXXXXX", g_get_user_name ());
+
+	return g_file_open_tmp (template, name_used, error);
+}
+
+/**
  * e_load_ui_definition:
  * @ui_manager: a #GtkUIManager
  * @basename: basename of the UI definition file

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	Mon Mar  9 03:31:24 2009
@@ -46,6 +46,8 @@
 						 const gchar *uri);
 void		e_display_help			(GtkWindow *parent,
 						 const gchar *link_id);
+gint		e_file_open_tmp			(gchar **name_used,
+						 GError **error);
 guint		e_load_ui_definition		(GtkUIManager *ui_manager,
 						 const gchar *basename);
 gint		e_action_compare_by_label	(GtkAction *action1,

Modified: branches/kill-bonobo/mail/em-composer-prefs.c
==============================================================================
--- branches/kill-bonobo/mail/em-composer-prefs.c	(original)
+++ branches/kill-bonobo/mail/em-composer-prefs.c	Mon Mar  9 03:31:24 2009
@@ -82,11 +82,13 @@
 {
 	GdkColor color;
 	const gchar *string;
-	gboolean success;
+	gboolean success = FALSE;
 
 	string = g_value_get_string (src_value);
-	if (gdk_color_parse (string, &color))
+	if (gdk_color_parse (string, &color)) {
 		g_value_set_boxed (dst_value, &color);
+		success = TRUE;
+	}
 
 	return success;
 }

Modified: branches/kill-bonobo/mail/em-folder-view.c
==============================================================================
--- branches/kill-bonobo/mail/em-folder-view.c	(original)
+++ branches/kill-bonobo/mail/em-folder-view.c	Mon Mar  9 03:31:24 2009
@@ -367,32 +367,6 @@
 	message_list_paste(emfv->list);
 }
 
-//static void
-//emfv_select_all_text(BonoboUIComponent *uid, void *data, const char *path)
-//{
-//	EMFolderView *emfv = data;
-//	gboolean selected;
-//
-//	gtk_html_select_all (((EMFormatHTML *)emfv->preview)->html);
-//	selected = gtk_html_command (((EMFormatHTML *)emfv->preview)->html, "is-selection-active");
-//	bonobo_ui_component_set_prop(emfv->uic, "/commands/EditCopy", "sensitive", selected?"1":"0", NULL);
-//
-//}
-
-static void
-emfv_message_search(BonoboUIComponent *uic, void *data, const char *path)
-{
-	EMFolderView *emfv = data;
-
-	if (!emfv->list_active) /* We are in new mail window */
-		em_format_html_display_search(emfv->preview);
-	else  {
-                /* We are in top level. Just grab focus to Search Bar */
-		gtk_widget_grab_focus (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->entry);
-		gtk_option_menu_set_history (GTK_OPTION_MENU (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->scopeoption), 3);
-	}
-}
-
 static void
 emp_uri_popup_vfolder_sender(EPopup *ep, EPopupItem *pitem, void *data)
 {
@@ -461,7 +435,7 @@
 //	BONOBO_UI_UNSAFE_VERB ("MessageDelete", emfv_message_delete),
 //	BONOBO_UI_UNSAFE_VERB ("MessageDeleteKey", emfv_message_delete),
 //	BONOBO_UI_UNSAFE_VERB ("MessageOpen", emfv_message_open),
-	BONOBO_UI_UNSAFE_VERB ("MessageSearch", emfv_message_search),
+//	BONOBO_UI_UNSAFE_VERB ("MessageSearch", emfv_message_search),
 
 //	BONOBO_UI_UNSAFE_VERB ("ViewSource", emfv_message_source),
 

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	Mon Mar  9 03:31:24 2009
@@ -1331,7 +1331,7 @@
 
 		if (!file) {
 			file = "attachment.dat";
-			new->file_name = g_strdup(file);
+			e_attachment_set_filename (new, file);
 		}
 
 		tmp = g_hash_table_lookup (efhd->priv->files, file);
@@ -1349,8 +1349,8 @@
 
 			g_free (tmp_file);
 			g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(count));
-			g_free (new->file_name);
-			new->file_name = new_file;
+			e_attachment_set_filename (new, new_file);
+			g_free (new_file);
 		} else {
 			g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1));
 		}
@@ -1562,8 +1562,13 @@
 
 	attachment_parts = e_attachment_bar_get_selected(E_ATTACHMENT_BAR(widget));
 
-	for (tmp = attachment_parts; tmp; tmp=tmp->next)
-		parts = g_slist_prepend(parts, ((EAttachment *)tmp->data)->body);
+	for (tmp = attachment_parts; tmp; tmp=tmp->next) {
+		EAttachment *attachment = tmp->data;
+		CamelMimePart *mime_part;
+
+		mime_part = e_attachment_get_mime_part (attachment);
+		parts = g_slist_prepend (parts, mime_part);
+	}
 
 	parts = g_slist_reverse(parts);
 	em_utils_save_parts(parent, _("Select folder to save selected attachments..."), parts);
@@ -1721,7 +1726,7 @@
 	GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image, *save, *scroll;
 	int width, height, bar_width;
 
-	priv->attachment_bar = e_attachment_bar_new(NULL);
+	priv->attachment_bar = e_attachment_bar_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;

Modified: branches/kill-bonobo/mail/em-popup.c
==============================================================================
--- branches/kill-bonobo/mail/em-popup.c	(original)
+++ branches/kill-bonobo/mail/em-popup.c	Mon Mar  9 03:31:24 2009
@@ -382,10 +382,20 @@
 	if (len > 0)
 		mask &= ~ EM_POPUP_ATTACHMENTS_MANY;
 	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
+		EAttachment *attachment;
+		CamelMimePart *mime_part;
+		CamelContentType *mime_type;
+		CamelDataWrapper *data_wrapper;
+
+		attachment = attachments->data;
+		mime_part = e_attachment_get_mime_part (attachment);
+		mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type;
+		data_wrapper = camel_medium_get_content_object (
+			CAMEL_MEDIUM (mime_part));
 
-		if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*"))
+		if (camel_content_type_is (mime_type, "image", "*"))
 			mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE;
-		if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *) ((EAttachment *) attachments->data)->body)))
+		if (CAMEL_IS_MIME_MESSAGE (data_wrapper))
 			mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE;
 
 		mask &= ~ EM_POPUP_ATTACHMENTS_ONE;
@@ -408,9 +418,12 @@
 	gpointer parent;
 
 	/* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	widget = ep->target->widget;
@@ -429,9 +442,12 @@
 	unsigned int i=1;
 	CamelMimePart *part = NULL;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	if (!part)
@@ -503,9 +519,12 @@
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
@@ -519,9 +538,12 @@
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
@@ -535,9 +557,12 @@
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
@@ -551,9 +576,12 @@
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
+	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) t)->part;
 
 	/* TODO: have a emfv specific override so we can get the parent folder uri */
@@ -642,9 +670,12 @@
 	EPopupTarget *target = ep->target;
 	CamelMimePart *part;
 
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
+	if (target->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) target)->part;
 
 	path = em_utils_temp_save_part(target->widget, part, TRUE);
@@ -711,11 +742,13 @@
 	CamelMimePart *part;
 	CamelDataWrapper *content;
 	CamelStreamMem *mem;
-	
 
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
+	if (target->type == EM_POPUP_TARGET_ATTACHMENTS) {
+		EAttachment *attachment;
+
+		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data);
+		part = e_attachment_get_mime_part (attachment);
+	} else
 		part = ((EMPopupTargetPart *) target)->part;
 
 	if (!part)
@@ -774,6 +807,7 @@
 		EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target;
 		GSList *list = t->attachments;
 		EAttachment *attachment;
+		CamelMimePart *mime_part;
 
 		if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
 			items = NULL;
@@ -783,8 +817,9 @@
 
 		/* Only one attachment selected */
 		attachment = list->data;
-		mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body);
-		filename = camel_mime_part_get_filename(attachment->body);
+		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);
 
 		items = emp_attachment_object_popups;
 		len = LEN(emp_attachment_object_popups);

Modified: branches/kill-bonobo/mail/em-utils.c
==============================================================================
--- branches/kill-bonobo/mail/em-utils.c	(original)
+++ branches/kill-bonobo/mail/em-utils.c	Mon Mar  9 03:31:24 2009
@@ -71,7 +71,7 @@
 #include "e-util/e-account-utils.h"
 #include "e-util/e-dialog-utils.h"
 #include "e-util/e-error.h"
-
+#include "widgets/misc/e-alert-activity.h"
 
 #include "em-utils.h"
 #include "em-composer-utils.h"
@@ -814,7 +814,7 @@
 		camel_tag_list_free (&tags);
 
 		if (ted->emfv->preview)
-			em_format_redraw(ted->emfv->preview);
+			em_format_redraw (EM_FORMAT (ted->emfv->preview));
 	}
 
 	gtk_widget_destroy (dialog);
@@ -2407,8 +2407,7 @@
 {
 	EActivity *activity;
 
-	activity = e_activity_new (NULL);
-	e_activity_error (activity, widget);
+	activity = e_alert_activity_new_warning (widget);
 	e_shell_module_add_activity (mail_shell_module, activity);
 	g_object_unref (activity);
 
@@ -2423,8 +2422,7 @@
 {
 	EActivity *activity;
 
-	activity = e_activity_new (NULL);
-	e_activity_info (activity, widget);
+	activity = e_alert_activity_new_info (widget);
 	e_shell_module_add_activity (mail_shell_module, activity);
 	g_object_unref (activity);
 

Modified: branches/kill-bonobo/mail/mail-mt.c
==============================================================================
--- branches/kill-bonobo/mail/mail-mt.c	(original)
+++ branches/kill-bonobo/mail/mail-mt.c	Mon Mar  9 03:31:24 2009
@@ -37,7 +37,7 @@
 #include "misc/e-gui-utils.h"
 #include "e-util/e-error.h"
 #include "e-util/e-icon-factory.h"
-#include "widgets/misc/e-activity.h"
+#include "widgets/misc/e-alert-activity.h"
 
 #include "mail-config.h"
 #include "mail-session.h"
@@ -145,12 +145,13 @@
 	if (error == NULL) {
 		e_activity_complete (activity);
 		g_object_unref (activity);
-	} else if (activity == NULL) {
-		activity = e_activity_new (NULL);
-		e_activity_error (activity, error);
+	} else {
+		if (activity != NULL)
+			g_object_unref (activity);
+		activity = e_alert_activity_new_warning (error);
 		e_shell_module_add_activity (mail_shell_module, activity);
-	} else
-		e_activity_error (activity, error);
+		g_object_unref (activity);
+	}
 }
 
 

Modified: branches/kill-bonobo/plugins/attachment-reminder/Makefile.am
==============================================================================
--- branches/kill-bonobo/plugins/attachment-reminder/Makefile.am	(original)
+++ branches/kill-bonobo/plugins/attachment-reminder/Makefile.am	Mon Mar  9 03:31:24 2009
@@ -1,6 +1,7 @@
 INCLUDES =						\
 	-I$(top_builddir)/composer			\
 	-I$(top_srcdir)					\
+	-I$(top_srcdir)/widgets				\
 	$(EVOLUTION_MAIL_CFLAGS)			\
 	-DEVOLUTION_PLUGINDIR="\"$(plugindir)\""
 
@@ -23,7 +24,7 @@
 liborg_gnome_evolution_attachment_reminder_la_LIBADD =	\
 	$(top_builddir)/e-util/libeutil.la		\
 	$(top_builddir)/widgets/misc/libemiscwidgets.la	\
-	$(top_builddir)/mail/libevolution-mail.la	\
+	$(top_builddir)/mail/libevolution-module-mail.la	\
 	$(EVOLUTION_MAIL_LIBS)
 
 schemadir       = $(GCONF_SCHEMA_FILE_DIR)

Modified: branches/kill-bonobo/shell/e-shell-window.c
==============================================================================
--- branches/kill-bonobo/shell/e-shell-window.c	(original)
+++ branches/kill-bonobo/shell/e-shell-window.c	Mon Mar  9 03:31:24 2009
@@ -60,6 +60,7 @@
 
 	/* Determine the page number for the new shell view. */
 	notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook);
+	page_num = gtk_notebook_get_n_pages (notebook);
 
 	/* Get the switcher action for this view. */
 	action = e_shell_window_get_shell_view_action (

Modified: branches/kill-bonobo/widgets/misc/Makefile.am
==============================================================================
--- branches/kill-bonobo/widgets/misc/Makefile.am	(original)
+++ branches/kill-bonobo/widgets/misc/Makefile.am	Mon Mar  9 03:31:24 2009
@@ -17,7 +17,6 @@
 
 privsolib_LTLIBRARIES =		\
 	libemiscwidgets.la
-#	libefilterbar.la
 
 widgetsincludedir = $(privincludedir)/misc
 
@@ -39,51 +38,55 @@
 	e-action-combo-box.h			\
 	e-activity.h				\
 	e-activity-proxy.h			\
-	e-attachment-bar.h			\
+	e-alert-activity.h			\
 	e-attachment.h				\
-	e-spinner.c				\
-	e-spinner.h				\
+	e-attachment-bar.h			\
+	e-attachment-dialog.h			\
 	e-calendar.h				\
 	e-calendar-item.h			\
+	e-canvas.h				\
+	e-canvas-background.h			\
+	e-canvas-utils.h			\
+	e-canvas-vbox.h				\
 	e-cell-date-edit.h			\
 	e-cell-percent.h			\
 	e-cell-renderer-combo.h			\
 	e-charset-picker.h			\
+	e-colors.h				\
 	e-combo-cell-editable.h			\
+	e-cursors.h				\
 	e-dateedit.h				\
 	e-expander.h				\
+	e-gui-utils.h				\
+	e-hsv-utils.h				\
 	e-icon-entry.h				\
 	e-image-chooser.h			\
 	e-map.h					\
 	e-menu-tool-button.h			\
-	e-popup-action.h			\
-	e-preferences-window.h			\
+	e-mime-part-utils.h			\
 	e-online-button.h			\
-	e-search-bar.h				\
-	e-send-options.h			\
-	e-url-entry.h				\
-	e-canvas-background.h			\
-	e-canvas-utils.h			\
-	e-canvas-vbox.h				\
-	e-canvas.h				\
-	e-cursors.h				\
-	e-gui-utils.h				\
-	e-hsv-utils.h				\
+	e-popup-action.h			\
 	e-popup-menu.h				\
+	e-preferences-window.h			\
 	e-printable.h				\
-	e-reflow-model.h			\
 	e-reflow.h				\
+	e-reflow-model.h			\
+	e-search-bar.h				\
+	e-selection-model.h			\
 	e-selection-model-array.h		\
 	e-selection-model-simple.h		\
-	e-selection-model.h			\
+	e-send-options.h			\
 	e-signature-combo-box.h			\
 	e-signature-editor.h			\
 	e-signature-manager.h			\
 	e-signature-preview.h			\
 	e-signature-script-dialog.h		\
 	e-signature-tree-view.h			\
+	e-spinner.c				\
+	e-spinner.h				\
+	e-timeout-activity.h			\
 	e-unicode.h				\
-	e-colors.h
+	e-url-entry.h
 
 libemiscwidgets_la_SOURCES =			\
 	$(widgetsinclude_HEADERS)		\
@@ -92,54 +95,57 @@
 	e-action-combo-box.c			\
 	e-activity.c				\
 	e-activity-proxy.c			\
-	e-calendar.c				\
+	e-alert-activity.c			\
 	e-attachment.c				\
 	e-attachment-bar.c			\
+	e-attachment-dialog.c			\
+	e-calendar.c				\
 	e-calendar-item.c			\
+	e-canvas.c				\
+	e-canvas-background.c			\
+	e-canvas-utils.c			\
+	e-canvas-vbox.c				\
 	e-cell-date-edit.c			\
 	e-cell-percent.c			\
 	e-cell-renderer-combo.c			\
 	e-charset-picker.c			\
+	e-colors.c				\
 	e-combo-cell-editable.c			\
+	e-cursors.c				\
 	e-dateedit.c				\
 	e-expander.c				\
+	e-gui-utils.c				\
+	e-hsv-utils.c				\
 	e-icon-entry.c				\
 	e-image-chooser.c			\
 	e-map.c					\
 	e-menu-tool-button.c			\
-	e-popup-action.c			\
-	e-preferences-window.c			\
+	e-mime-part-utils.c			\
 	e-online-button.c			\
-	e-search-bar.c				\
-	e-send-options.c			\
-	e-url-entry.c				\
-	e-canvas-background.c			\
-	e-canvas-utils.c			\
-	e-canvas-vbox.c				\
-	e-canvas.c				\
-	e-cursors.c				\
-	e-gui-utils.c				\
-	e-hsv-utils.c				\
+	e-popup-action.c			\
 	e-popup-menu.c				\
+	e-preferences-window.c			\
 	e-printable.c				\
 	e-reflow-model.c			\
 	e-reflow.c				\
+	e-search-bar.c				\
+	e-selection-model.c			\
 	e-selection-model-array.c		\
 	e-selection-model-simple.c		\
-	e-selection-model.c			\
+	e-send-options.c			\
 	e-signature-combo-box.c			\
 	e-signature-editor.c			\
 	e-signature-manager.c			\
 	e-signature-preview.c			\
 	e-signature-script-dialog.c		\
 	e-signature-tree-view.c			\
+	e-timeout-activity.c			\
 	e-unicode.c				\
-	e-colors.c
-
+	e-url-entry.c
 
 libemiscwidgets_la_LDFLAGS = $(NO_UNDEFINED)
 
-libemiscwidgets_la_LIBADD = $(top_builddir)/e-util/libeutil.la		\
+libemiscwidgets_la_LIBADD = \
 	$(top_builddir)/e-util/libeutil.la				\
 	$(top_builddir)/filter/libfilter.la				\
 	$(top_builddir)/widgets/table/libetable.la			\
@@ -148,20 +154,8 @@
 	$(top_builddir)/a11y/libevolution-a11y.la			\
 	$(EVOLUTION_MAIL_LIBS)						\
 	$(GNOME_PLATFORM_LIBS)						\
-	$(EVOLUTON_MAIL_LIBS)						\
 	$(ICONV_LIBS)
 
-#libefilterbar_la_SOURCES =	\
-#	e-filter-bar.c		\
-#	e-filter-bar.h
-#
-#libefilterbar_la_LDFLAGS = $(NO_UNDEFINED)
-#
-#libefilterbar_la_LIBADD =			\
-#	$(WIN32_BOOTSTRAP_LIBS)			\
-#	libemiscwidgets.la			\
-#	$(E_WIDGETS_LIBS)
-
 noinst_PROGRAMS = 			\
 	test-calendar			\
 	test-dateedit			\

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	Mon Mar  9 03:31:24 2009
@@ -32,7 +32,6 @@
 	gchar *primary_text;
 	gchar *secondary_text;
 	gdouble percent;
-	guint timeout_id;
 
 	guint blocking		: 1;
 	guint cancellable	: 1;
@@ -56,21 +55,12 @@
 	CANCELLED,
 	CLICKED,
 	COMPLETED,
-	TIMEOUT,
 	LAST_SIGNAL
 };
 
 static gpointer parent_class;
 static gulong signals[LAST_SIGNAL];
 
-static gboolean
-activity_timeout_cb (EActivity *activity)
-{
-	g_signal_emit (activity, signals[TIMEOUT], 0);
-
-	return FALSE;
-}
-
 static void
 activity_set_property (GObject *object,
                        guint property_id,
@@ -188,13 +178,64 @@
 	g_free (priv->primary_text);
 	g_free (priv->secondary_text);
 
-	if (priv->timeout_id > 0)
-		g_source_remove (priv->timeout_id);
-
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static gchar *
+activity_describe (EActivity *activity)
+{
+	GString *string;
+	const gchar *text;
+	gboolean cancelled;
+	gboolean completed;
+	gdouble percent;
+
+	string = g_string_sized_new (256);
+	text = e_activity_get_primary_text (activity);
+	cancelled = e_activity_is_cancelled (activity);
+	completed = e_activity_is_completed (activity);
+	percent = e_activity_get_percent (activity);
+
+	if (cancelled) {
+		/* Translators: This is a cancelled activity. */
+		g_string_printf (string, _("%s (cancelled)"), text);
+	} else if (completed) {
+		/* Translators: This is a completed activity. */
+		g_string_printf (string, _("%s (completed)"), text);
+	} else if (percent < 0.0) {
+		/* Translators: This is an activity whose percent
+		 * complete is unknown. */
+		g_string_printf (string, _("%s..."), text);
+	} else {
+		/* Translators: This is an activity whose percent
+		 * complete is known. */
+		g_string_printf (
+			string, _("%s (%d%% complete)"), text,
+			(gint) (percent * 100.0 + 0.5));
+	}
+
+	return g_string_free (string, FALSE);
+}
+
+static void
+activity_cancelled (EActivity *activity)
+{
+	activity->priv->cancelled = TRUE;
+}
+
+static void
+activity_completed (EActivity *activity)
+{
+	activity->priv->completed = TRUE;
+}
+
+static void
+activity_clicked (EActivity *activity)
+{
+	/* Allow subclasses to safely chain up. */
+}
+
 static void
 activity_class_init (EActivityClass *class)
 {
@@ -208,6 +249,11 @@
 	object_class->get_property = activity_get_property;
 	object_class->finalize = activity_finalize;
 
+	class->describe = activity_describe;
+	class->cancelled = activity_cancelled;
+	class->completed = activity_completed;
+	class->clicked = activity_clicked;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_BLOCKING,
@@ -291,7 +337,8 @@
 		"cancelled",
 		G_OBJECT_CLASS_TYPE (object_class),
 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		0, NULL, NULL,
+		G_STRUCT_OFFSET (EActivityClass, cancelled),
+		NULL, NULL,
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
 
@@ -299,7 +346,8 @@
 		"clicked",
 		G_OBJECT_CLASS_TYPE (object_class),
 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		0, NULL, NULL,
+		G_STRUCT_OFFSET (EActivityClass, clicked),
+		NULL, NULL,
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
 
@@ -307,15 +355,8 @@
 		"completed",
 		G_OBJECT_CLASS_TYPE (object_class),
 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		0, NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
-	signals[TIMEOUT] = g_signal_new (
-		"timeout",
-		G_OBJECT_CLASS_TYPE (object_class),
-		G_SIGNAL_RUN_FIRST,
-		0, NULL, NULL,
+		G_STRUCT_OFFSET (EActivityClass, completed),
+		NULL, NULL,
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
 }
@@ -372,7 +413,6 @@
 	if (activity->priv->completed)
 		return;
 
-	activity->priv->cancelled = TRUE;
 	g_signal_emit (activity, signals[CANCELLED], 0);
 }
 
@@ -387,7 +427,6 @@
 	if (activity->priv->completed)
 		return;
 
-	activity->priv->completed = TRUE;
 	g_signal_emit (activity, signals[COMPLETED], 0);
 }
 
@@ -402,39 +441,14 @@
 gchar *
 e_activity_describe (EActivity *activity)
 {
-	GString *string;
-	const gchar *text;
-	gboolean cancelled;
-	gboolean completed;
-	gdouble percent;
+	EActivityClass *class;
 
 	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 
-	string = g_string_sized_new (256);
-	text = e_activity_get_primary_text (activity);
-	cancelled = e_activity_is_cancelled (activity);
-	completed = e_activity_is_completed (activity);
-	percent = e_activity_get_percent (activity);
-
-	if (cancelled) {
-		/* Translators: This is a cancelled activity. */
-		g_string_printf (string, _("%s (cancelled)"), text);
-	} else if (completed) {
-		/* Translators: This is a completed activity. */
-		g_string_printf (string, _("%s (completed)"), text);
-	} else if (percent < 0.0) {
-		/* Translators: This is an activity whose percent
-		 * complete is unknown. */
-		g_string_printf (string, _("%s..."), text);
-	} else {
-		/* Translators: This is an activity whose percent
-		 * complete is known. */
-		g_string_printf (
-			string, _("%s (%d%% complete)"), text,
-			(gint) (percent * 100.0 + 0.5));
-	}
+	class = E_ACTIVITY_GET_CLASS (activity);
+	g_return_val_if_fail (class->describe != NULL, NULL);
 
-	return g_string_free (string, FALSE);
+	return class->describe (activity);
 }
 
 gboolean
@@ -453,29 +467,6 @@
 	return activity->priv->completed;
 }
 
-void
-e_activity_add_timeout (EActivity *activity,
-                        guint seconds)
-{
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-
-	e_activity_cancel_timeout (activity);
-
-	activity->priv->timeout_id = g_timeout_add_seconds (
-		seconds, (GSourceFunc) activity_timeout_cb, activity);
-}
-
-void
-e_activity_cancel_timeout (EActivity *activity)
-{
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-
-	if (activity->priv->timeout_id > 0) {
-		g_source_remove (activity->priv->timeout_id);
-		activity->priv->timeout_id = 0;
-	}
-}
-
 gboolean
 e_activity_get_blocking (EActivity *activity)
 {
@@ -611,105 +602,3 @@
 
 	g_object_notify (G_OBJECT (activity), "secondary-text");
 }
-
-/************************* Error Dialog Integration **************************/
-
-void
-e_activity_error (EActivity *activity,
-                  GtkWidget *error_dialog)
-{
-	GObject *object;
-	const gchar *primary_text;
-	const gchar *secondary_text;
-
-	/* XXX Convert an activity to a clickable error message.
-	 *     Clicking on the activity completes it and displays
-	 *     the error dialog.  Eventually I'd like to eliminate
-	 *     error dialogs altogether and show errors directly
-	 *     in the shell window. */
-
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-	g_return_if_fail (GTK_IS_DIALOG (error_dialog));
-
-	object = G_OBJECT (error_dialog);
-	primary_text = g_object_get_data (object, "primary");
-	secondary_text = g_object_get_data (object, "secondary");
-
-	e_activity_set_primary_text (activity, primary_text);
-	e_activity_set_secondary_text (activity, secondary_text);
-	e_activity_set_icon_name (activity, "dialog-warning");
-	e_activity_set_clickable (activity, TRUE);
-
-	g_signal_connect (
-		activity, "cancelled",
-		G_CALLBACK (e_activity_cancel_timeout), NULL);
-
-	g_signal_connect (
-		activity, "completed",
-		G_CALLBACK (e_activity_cancel_timeout), NULL);
-
-	g_signal_connect (
-		activity, "clicked",
-		G_CALLBACK (e_activity_complete), NULL);
-
-	g_signal_connect_swapped (
-		activity, "clicked",
-		G_CALLBACK (gtk_dialog_run), error_dialog);
-
-	g_signal_connect (
-		activity, "timeout",
-		G_CALLBACK (e_activity_complete), NULL);
-
-	/* XXX Allow for a configurable timeout. */
-	e_activity_add_timeout (activity, 60);
-}
-
-void
-e_activity_info (EActivity *activity,
-                 GtkWidget *info_dialog)
-{
-	GObject *object;
-	const gchar *primary_text;
-	const gchar *secondary_text;
-
-	/* XXX Convert an activity to a clickable info message.
-	 *     Clicking on the activity completes it and displays
-	 *     the info dialog.  Eventually I'd like to eliminate
-	 *     info dialogs altogether and show errors directly
-	 *     in the shell window. */
-
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-	g_return_if_fail (GTK_IS_DIALOG (info_dialog));
-
-	object = G_OBJECT (info_dialog);
-	primary_text = g_object_get_data (object, "primary");
-	secondary_text = g_object_get_data (object, "secondary");
-
-	e_activity_set_primary_text (activity, primary_text);
-	e_activity_set_secondary_text (activity, secondary_text);
-	e_activity_set_icon_name (activity, "dialog-warning");
-	e_activity_set_clickable (activity, TRUE);
-
-	g_signal_connect (
-		activity, "cancelled",
-		G_CALLBACK (e_activity_cancel_timeout), NULL);
-
-	g_signal_connect (
-		activity, "completed",
-		G_CALLBACK (e_activity_cancel_timeout), NULL);
-
-	g_signal_connect (
-		activity, "clicked",
-		G_CALLBACK (e_activity_complete), NULL);
-
-	g_signal_connect_swapped (
-		activity, "clicked",
-		G_CALLBACK (gtk_dialog_run), info_dialog);
-
-	g_signal_connect (
-		activity, "timeout",
-		G_CALLBACK (e_activity_complete), NULL);
-
-	/* XXX Allow for a configurable timeout. */
-	e_activity_add_timeout (activity, 60);
-}

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	Mon Mar  9 03:31:24 2009
@@ -56,6 +56,14 @@
 
 struct _EActivityClass {
 	GObjectClass parent_class;
+
+	/* Methods */
+	gchar *		(*describe)		(EActivity *activity);
+
+	/* Signals */
+	void		(*cancelled)		(EActivity *activity);
+	void		(*completed)		(EActivity *activity);
+	void		(*clicked)		(EActivity *activity);
 };
 
 GType		e_activity_get_type		(void);
@@ -66,9 +74,6 @@
 gchar *		e_activity_describe		(EActivity *activity);
 gboolean	e_activity_is_cancelled		(EActivity *activity);
 gboolean	e_activity_is_completed		(EActivity *activity);
-void		e_activity_add_timeout		(EActivity *activity,
-						 guint seconds);
-void		e_activity_cancel_timeout	(EActivity *activity);
 gboolean	e_activity_get_blocking		(EActivity *activity);
 void		e_activity_set_blocking		(EActivity *activity,
 						 gboolean blocking);
@@ -91,12 +96,6 @@
 void		e_activity_set_secondary_text	(EActivity *activity,
 						 const gchar *secondary_text);
 
-/* XXX Hacky integration with error dialogs. */
-void		e_activity_error		(EActivity *activity,
-						 GtkWidget *error_dialog);
-void		e_activity_info			(EActivity *activity,
-						 GtkWidget *info_dialog);
-
 G_END_DECLS
 
 #endif /* E_ACTIVITY_H */

Added: branches/kill-bonobo/widgets/misc/e-alert-activity.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-alert-activity.c	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,254 @@
+/*
+ * e-alert-activity.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-alert-activity.h"
+
+#define E_ALERT_ACTIVITY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityPrivate))
+
+struct _EAlertActivityPrivate {
+	GtkWidget *message_dialog;
+};
+
+enum {
+	PROP_0,
+	PROP_MESSAGE_DIALOG
+};
+
+static gpointer parent_class;
+
+static void
+alert_activity_set_message_dialog (EAlertActivity *alert_activity,
+                                   GtkWidget *message_dialog)
+{
+	g_return_if_fail (alert_activity->priv->message_dialog == NULL);
+
+	alert_activity->priv->message_dialog = g_object_ref (message_dialog);
+}
+
+static void
+alert_activity_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_MESSAGE_DIALOG:
+			alert_activity_set_message_dialog (
+				E_ALERT_ACTIVITY (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_MESSAGE_DIALOG:
+			g_value_set_object (
+				value, e_alert_activity_get_message_dialog (
+				E_ALERT_ACTIVITY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_dispose (GObject *object)
+{
+	EAlertActivityPrivate *priv;
+
+	priv = E_ALERT_ACTIVITY_GET_PRIVATE (object);
+
+	if (priv->message_dialog != NULL) {
+		g_object_unref (priv->message_dialog);
+		priv->message_dialog = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+alert_activity_constructed (GObject *object)
+{
+	EActivity *activity;
+	EAlertActivity *alert_activity;
+	GtkWidget *message_dialog;
+	const gchar *primary_text;
+	const gchar *secondary_text;
+
+	alert_activity = E_ALERT_ACTIVITY (object);
+	message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+
+	object = G_OBJECT (message_dialog);
+	primary_text = g_object_get_data (object, "primary");
+	secondary_text = g_object_get_data (object, "secondary");
+
+	activity = E_ACTIVITY (alert_activity);
+	e_activity_set_primary_text (activity, primary_text);
+	e_activity_set_secondary_text (activity, secondary_text);
+}
+
+static void
+alert_activity_clicked (EActivity *activity)
+{
+	EAlertActivity *alert_activity;
+	GtkWidget *message_dialog;
+
+	e_activity_complete (activity);
+
+	alert_activity = E_ALERT_ACTIVITY (activity);
+	message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+	gtk_dialog_run (GTK_DIALOG (message_dialog));
+	gtk_widget_hide (message_dialog);
+
+	/* Chain up to parent's clicked() method. */
+	E_ACTIVITY_CLASS (parent_class)->clicked (activity);
+}
+
+static void
+alert_activity_timeout (ETimeoutActivity *activity)
+{
+	e_activity_complete (E_ACTIVITY (activity));
+
+	/* Chain up to parent's timeout() method. */
+	E_TIMEOUT_ACTIVITY_CLASS (parent_class)->timeout (activity);
+}
+
+static void
+alert_activity_class_init (EAlertActivityClass *class)
+{
+	GObjectClass *object_class;
+	EActivityClass *activity_class;
+	ETimeoutActivityClass *timeout_activity_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAlertActivityPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = alert_activity_set_property;
+	object_class->get_property = alert_activity_get_property;
+	object_class->dispose = alert_activity_dispose;
+	object_class->constructed = alert_activity_constructed;
+
+	activity_class = E_ACTIVITY_CLASS (class);
+	activity_class->clicked = alert_activity_clicked;
+
+	timeout_activity_class = E_TIMEOUT_ACTIVITY_CLASS (class);
+	timeout_activity_class->timeout = alert_activity_timeout;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MESSAGE_DIALOG,
+		g_param_spec_object (
+			"message-dialog",
+			NULL,
+			NULL,
+			GTK_TYPE_DIALOG,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+alert_activity_init (EAlertActivity *alert_activity)
+{
+	alert_activity->priv = E_ALERT_ACTIVITY_GET_PRIVATE (alert_activity);
+
+	e_activity_set_clickable (E_ACTIVITY (alert_activity), TRUE);
+	e_timeout_activity_set_timeout (E_TIMEOUT_ACTIVITY (alert_activity), 60);
+}
+
+GType
+e_alert_activity_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAlertActivityClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) alert_activity_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EAlertActivity),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) alert_activity_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_TIMEOUT_ACTIVITY, "EAlertActivity",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+EActivity *
+e_alert_activity_new_info (GtkWidget *message_dialog)
+{
+	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+	return g_object_new (
+		E_TYPE_ALERT_ACTIVITY,
+		"icon-name", "dialog-information",
+		"message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_error (GtkWidget *message_dialog)
+{
+	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+	return g_object_new (
+		E_TYPE_ALERT_ACTIVITY,
+		"icon-name", "dialog-error",
+		"message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_warning (GtkWidget *message_dialog)
+{
+	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+	return g_object_new (
+		E_TYPE_ALERT_ACTIVITY,
+		"icon-name", "dialog-warning",
+		"message-dialog", message_dialog, NULL);
+}
+
+GtkWidget *
+e_alert_activity_get_message_dialog (EAlertActivity *alert_activity)
+{
+	g_return_val_if_fail (E_IS_ALERT_ACTIVITY (alert_activity), NULL);
+
+	return alert_activity->priv->message_dialog;
+}

Added: branches/kill-bonobo/widgets/misc/e-alert-activity.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-alert-activity.h	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,70 @@
+/*
+ * e-alert-activity.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_ALERT_ACTIVITY_H
+#define E_ALERT_ACTIVITY_H
+
+#include <e-timeout-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ALERT_ACTIVITY \
+	(e_alert_activity_get_type ())
+#define E_ALERT_ACTIVITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivity))
+#define E_ALERT_ACTIVITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+#define E_IS_ALERT_ACTIVITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ALERT_ACTIVITY))
+#define E_IS_ALERT_ACTIVITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ALERT_ACTIVITY))
+#define E_ALERT_ACTIVITY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAlertActivity EAlertActivity;
+typedef struct _EAlertActivityClass EAlertActivityClass;
+typedef struct _EAlertActivityPrivate EAlertActivityPrivate;
+
+struct _EAlertActivity {
+	ETimeoutActivity parent;
+	EAlertActivityPrivate *priv;
+};
+
+struct _EAlertActivityClass {
+	ETimeoutActivityClass parent_class;
+};
+
+GType		e_alert_activity_get_type	(void);
+EActivity *	e_alert_activity_new_info	(GtkWidget *message_dialog);
+EActivity *	e_alert_activity_new_error	(GtkWidget *message_dialog);
+EActivity *	e_alert_activity_new_warning	(GtkWidget *message_dialog);
+GtkWidget *	e_alert_activity_get_message_dialog
+						(EAlertActivity *alert_activity);
+
+G_END_DECLS
+
+#endif /* E_ALERT_ACTIVITY_H */

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	Mon Mar  9 03:31:24 2009
@@ -43,6 +43,7 @@
 
 #include "e-attachment.h"
 #include "e-attachment-bar.h"
+#include "e-mime-part-utils.h"
 
 #include <libedataserver/e-data-server-util.h>
 
@@ -56,11 +57,13 @@
 #include <camel/camel-mime-filter-bestenc.h>
 #include <camel/camel-mime-part.h>
 
-#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/e-error.h"
 #include "e-util/e-gui-utils.h"
 #include "e-util/e-icon-factory.h"
-#include "e-util/e-error.h"
 #include "e-util/e-mktemp.h"
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
 
 #define ICON_WIDTH 64
 #define ICON_SEPARATORS " /-_"
@@ -70,84 +73,418 @@
 #define ICON_BORDER 2
 #define ICON_TEXT_SPACING 2
 
-
-static GnomeIconListClass *parent_class = NULL;
+#define E_ATTACHMENT_BAR_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarPrivate))
 
 struct _EAttachmentBarPrivate {
-	GtkWidget *attach;	/* attachment file dialogue, if active */
-
 	gboolean batch_unref;
 	GPtrArray *attachments;
+	gchar *current_folder;
 	char *path;
+
+	GtkUIManager *ui_manager;
+	GtkActionGroup *standard_actions;
+	GtkActionGroup *editable_actions;
+	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
 };
 
-
 enum {
 	CHANGED,
+	UPDATE_ACTIONS,
 	LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = { 0 };
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
 
-
-static void update (EAttachmentBar *bar);
+static const gchar *ui =
+"<ui>"
+"  <popup name='attachment-popup'>"
+"    <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>"
+"</ui>";
 
-/* Attachment handling functions.  */
+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
-attachment_destroy (EAttachmentBar *bar, EAttachment *attachment)
+action_properties_cb (GtkAction *action,
+                      EAttachmentBar *attachment_bar)
 {
-	if (bar->priv->batch_unref)
-		return;
+	GnomeIconList *icon_list;
+	GPtrArray *array;
+	GList *selection;
+	gpointer parent;
 
-	if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
-		update (bar);
-		g_signal_emit (bar, signals[CHANGED], 0);
+	array = attachment_bar->priv->attachments;
+
+	icon_list = GNOME_ICON_LIST (attachment_bar);
+	selection = gnome_icon_list_get_selection (icon_list);
+	g_return_if_fail (selection != NULL);
+
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (icon_list));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	while (selection != NULL) {
+		gint index = GPOINTER_TO_INT (selection->data);
+		EAttachment *attachment;
+
+		selection = g_list_next (selection);
+
+		if (index >= array->len)
+			continue;
+
+		attachment = array->pdata[index];
+		e_attachment_edit (attachment, parent);
 	}
 }
 
 static void
-attachment_changed_cb (EAttachment *attachment,
-		       gpointer data)
+action_recent_cb (GtkAction *action,
+                  EAttachmentBar *attachment_bar)
 {
-	update (E_ATTACHMENT_BAR (data));
+	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
-add_common (EAttachmentBar *bar, EAttachment *attachment)
+action_remove_cb (GtkAction *action,
+                  EAttachmentBar *attachment_bar)
 {
-	g_return_if_fail (attachment != NULL);
+	GnomeIconList *icon_list;
+	GPtrArray *array;
+	GList *selection;
+	GList *trash = NULL;
 
-	g_ptr_array_add (bar->priv->attachments, attachment);
-	g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-	g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
+	array = attachment_bar->priv->attachments;
 
-	update (bar);
+	icon_list = GNOME_ICON_LIST (attachment_bar);
+	selection = gnome_icon_list_get_selection (icon_list);
+	g_return_if_fail (selection != NULL);
 
-	g_signal_emit (bar, signals[CHANGED], 0);
+	while (selection != NULL) {
+		gint index = GPOINTER_TO_INT (selection->data);
+
+		selection = g_list_next (selection);
+
+		if (index >= array->len)
+			continue;
+
+		/* We can't unref the attachment here because that may
+		 * change the selection and invalidate the list we are
+		 * iterating over.  So move it to a trash list instead. */
+		trash = g_list_prepend (trash, array->pdata[index]);
+		array->pdata[index] = NULL;
+	}
+
+	/* Compress the attachment array. */
+	while (g_ptr_array_remove (array, NULL));
+
+	/* Take out the trash. */
+	g_list_foreach (trash, (GFunc) g_object_unref, NULL);
+	g_list_free (trash);
+
+	e_attachment_bar_refresh (attachment_bar);
+
+	g_signal_emit (attachment_bar, signals[CHANGED], 0);
 }
 
 static void
-add_from_mime_part (EAttachmentBar *bar, CamelMimePart *part)
+action_save_as_cb (GtkAction *action,
+                   EAttachmentBar *attachment_bar)
 {
-	add_common (bar, e_attachment_new_from_mime_part (part));
 }
 
 static void
-add_from_file (EAttachmentBar *bar, const char *file_name, const char *disposition)
+action_set_background_cb (GtkAction *action,
+                          EAttachmentBar *attachment_bar)
 {
+	GnomeIconList *icon_list;
+	CamelContentType *content_type;
+	CamelMimePart *mime_part;
 	EAttachment *attachment;
-	CamelException ex;
+	GPtrArray *array;
+	GList *selection;
+	gchar *basename;
+	gchar *filename;
+	gchar *dirname;
+	GFile *file;
+	gint index;
+	GError *error = NULL;
 
-	camel_exception_init (&ex);
+	icon_list = GNOME_ICON_LIST (attachment_bar);
+	selection = gnome_icon_list_get_selection (icon_list);
+	g_return_if_fail (selection != NULL);
+
+	array = attachment_bar->priv->attachments;
+	index = GPOINTER_TO_INT (selection->data);
+	attachment = E_ATTACHMENT (array->pdata[index]);
+	mime_part = e_attachment_get_mime_part (attachment);
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+	content_type = camel_mime_part_get_content_type (mime_part);
+	basename = g_strdup (camel_mime_part_get_filename (mime_part));
+
+	if (basename == NULL || basename == '\0') {
+		g_free (basename);
+		basename = g_strdup_printf (
+			_("untitled_image.%s"),
+			content_type->subtype);
+	}
+
+	dirname = g_build_filename (
+		g_get_home_dir (), ".gnome2", "wallpapers", NULL);
+
+	index = 0;
+	filename = g_build_filename (dirname, basename, NULL);
+
+	while (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		gchar *temp;
+		gchar *ext;
+
+		ext = strrchr (filename, '.');
+		if (ext != NULL)
+			*ext++ = '\0';
+
+		if (ext == NULL)
+			temp = g_strdup_printf (
+				"%s (%d)", basename, index++);
+		else
+			temp = g_strdup_printf (
+				"%s (%d).%s", basename, index++, ext);
 
-	if ((attachment = e_attachment_new (file_name, disposition, &ex))) {
-		add_common (bar, attachment);
-	} else {
-		/* FIXME: Avoid using error from mailer */
-		e_error_run ((GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar), "mail-composer:no-attach",
-			     file_name, camel_exception_get_description (&ex), NULL);
-		camel_exception_clear (&ex);
+		g_free (basename);
+		g_free (filename);
+		basename = temp;
+
+		filename = g_build_filename (dirname, basename, NULL);
+	}
+
+	g_free (basename);
+	g_free (dirname);
+
+	file = g_file_new_for_path (filename);
+
+	if (e_mime_part_utils_save_to_file (mime_part, file, &error)) {
+		const gchar *background_filename;
+		const gchar *background_options;
+
+		background_filename =
+			e_attachment_bar_get_background_filename (
+			attachment_bar);
+		background_options =
+			e_attachment_bar_get_background_options (
+			attachment_bar);
+
+		if (g_strcmp0 (background_filename, filename) == 0)
+			e_attachment_bar_set_background_filename (
+				attachment_bar, NULL);
+
+		e_attachment_bar_set_background_filename (
+			attachment_bar, filename);
+
+		if (g_strcmp0 (background_options, "none") == 0)
+			e_attachment_bar_set_background_options (
+				attachment_bar, "wallpaper");
+	}
+
+	g_object_unref (file);
+	g_free (filename);
+
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+}
+
+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)
+{
+	GtkUIManager *ui_manager;
+	GtkWidget *menu;
+
+	ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
+	menu = gtk_ui_manager_get_widget (ui_manager, "/attachment-popup");
+	g_return_if_fail (GTK_IS_MENU (menu));
+
+	e_attachment_bar_update_actions (attachment_bar);
+
+	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 ());
+}
+
+/* Attachment handling functions.  */
+
+static void
+attachment_destroy (EAttachmentBar *bar,
+                    EAttachment *attachment)
+{
+	if (bar->priv->batch_unref)
+		return;
+
+	if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
+		e_attachment_bar_refresh (bar);
+		g_signal_emit (bar, signals[CHANGED], 0);
 	}
 }
 
@@ -161,6 +498,7 @@
 {
 	GdkPixbuf *pixbuf = NULL;
 #ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
+	CamelMimePart *mime_part;
 	struct stat file_stat;
 	char *file_uri = NULL;
 	gboolean is_tmp = FALSE;
@@ -168,9 +506,11 @@
 	if (!attachment || !attachment->is_available_local)
 		return NULL;
 
+	mime_part = e_attachment_get_mime_part (attachment);
+
 	if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://"))
 		file_uri = attachment->store_uri;
-	else if (attachment->body) {
+	else if (mime_part != NULL) {
 		/* save part to the temp directory */
 		char *tmp_file;
 
@@ -182,7 +522,7 @@
 			char *mfilename = NULL;
 			const char * filename;
 
-			filename = camel_mime_part_get_filename (attachment->body);
+			filename = camel_mime_part_get_filename (mime_part);
 			if (filename == NULL)
 				filename = "unknown";
 			else {
@@ -202,7 +542,7 @@
 			if (stream) {
 				CamelDataWrapper *content;
 
-				content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+				content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 
 				if (camel_data_wrapper_decode_to_stream (content, stream) == -1
 				    || camel_stream_flush (stream) == -1) {
@@ -298,17 +638,24 @@
 /* Icon list contents handling.  */
 
 static void
-calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height)
+calculate_height_width (EAttachmentBar *bar,
+                        gint *new_width,
+                        gint *new_height)
 {
         int width, height, icon_width;
         PangoFontMetrics *metrics;
         PangoContext *context;
 
-        context = gtk_widget_get_pango_context ((GtkWidget *) bar);
-        metrics = pango_context_get_metrics (context, ((GtkWidget *) bar)->style->font_desc, pango_context_get_language (context));
-        width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)) * 15;
+        context = gtk_widget_get_pango_context (GTK_WIDGET (bar));
+        metrics = pango_context_get_metrics (
+		context, GTK_WIDGET (bar)->style->font_desc,
+		pango_context_get_language (context));
+        width = PANGO_PIXELS (
+		pango_font_metrics_get_approximate_char_width (metrics)) * 15;
 	/* This should be *2, but the icon list creates too much space above ... */
-	height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) * 3;
+	height = PANGO_PIXELS (
+		pango_font_metrics_get_ascent (metrics) +
+		pango_font_metrics_get_descent (metrics)) * 3;
 	pango_font_metrics_unref (metrics);
 	icon_width = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING;
 
@@ -316,21 +663,23 @@
 		*new_width = MAX (icon_width, width);
 
 	if (new_height)
-		*new_height = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING + height;
-
-	return;
+		*new_height = ICON_WIDTH + ICON_SPACING +
+			ICON_BORDER + ICON_TEXT_SPACING + height;
 }
 
 void
 e_attachment_bar_create_attachment_cache (EAttachment *attachment)
 {
-
 	CamelContentType *content_type;
+	CamelMimePart *mime_part;
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
-	if (!attachment->body)
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part == NULL)
 		return;
 
-	content_type = camel_mime_part_get_content_type (attachment->body);
+	content_type = camel_mime_part_get_content_type (mime_part);
 
 	if (camel_content_type_is(content_type, "image", "*")) {
 		CamelDataWrapper *wrapper;
@@ -339,7 +688,7 @@
 		gboolean error = TRUE;
 		GdkPixbuf *pixbuf;
 
-		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+		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);
@@ -350,12 +699,15 @@
 		gdk_pixbuf_loader_close (loader, NULL);
 
 		if (!error) {
+			/* The loader owns the reference. */
 			pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-			attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-			pixbuf = attachment->pixbuf_cache;
-			g_object_ref(pixbuf);
+
+			/* This returns a new GdkPixbuf. */
+			pixbuf = scale_pixbuf (pixbuf);
+			e_attachment_set_thumbnail (attachment, pixbuf);
+			g_object_unref (pixbuf);
 		} else {
-			attachment->pixbuf_cache = NULL;
+			e_attachment_set_thumbnail (attachment, NULL);
 			g_warning ("GdkPixbufLoader Error");
 		}
 
@@ -366,346 +718,111 @@
 }
 
 static void
-update (EAttachmentBar *bar)
+update_remote_file (EAttachment *attachment, EAttachmentBar *bar)
 {
-	struct _EAttachmentBarPrivate *priv;
 	GnomeIconList *icon_list;
-	int bar_width, bar_height;
-	int i;
+	GnomeIconTextItem *item;
+	const gchar *filename;
+	char *msg, *base;
+
+	if (attachment->percentage == -1) {
+		e_attachment_bar_refresh (bar);
+		return;
+	}
+
+	filename = e_attachment_get_filename (attachment);
+	base = g_path_get_basename (filename);
+	msg = g_strdup_printf ("%s (%d%%)", base, attachment->percentage);
+	g_free (base);
 
-	priv = bar->priv;
 	icon_list = GNOME_ICON_LIST (bar);
 
 	gnome_icon_list_freeze (icon_list);
 
-	gnome_icon_list_clear (icon_list);
+	item = gnome_icon_list_get_icon_text_item (
+		icon_list, attachment->index);
+	if (!item->is_text_allocated)
+		g_free (item->text);
 
-	/* FIXME could be faster, but we don't care.  */
-	for (i = 0; i < priv->attachments->len; i++) {
-		EAttachment *attachment;
-		CamelContentType *content_type;
-		char *size_string, *label;
-		GdkPixbuf *pixbuf = NULL;
-		const char *desc;
+	gnome_icon_text_item_configure (
+		item, item->x, item->y, item->width,
+		item->fontname, msg, item->is_editable, TRUE);
 
-		attachment = priv->attachments->pdata[i];
+	gnome_icon_list_thaw (icon_list);
+}
 
-		if (!attachment->is_available_local || !attachment->body) {
-			if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
-				attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
-				g_object_unref (pixbuf);
-			}
-			continue;
-		}
+void
+e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
+{
+	int per_col, rows, height, width;
 
-		content_type = camel_mime_part_get_content_type (attachment->body);
-		/* Get the image out of the attachment
-		   and create a thumbnail for it */
-		if ((pixbuf = attachment->pixbuf_cache)) {
-			g_object_ref(pixbuf);
-		} else if (camel_content_type_is(content_type, "image", "*")) {
-			CamelDataWrapper *wrapper;
-			CamelStreamMem *mstream;
-			GdkPixbufLoader *loader;
-			gboolean error = TRUE;
+	calculate_height_width(bar, &width, &height);
+	per_col = bar_width / width;
+	per_col = (per_col ? per_col : 1);
+	rows = (bar->priv->attachments->len + per_col - 1) / per_col;
+	gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height);
+}
 
-			wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-			mstream = (CamelStreamMem *) camel_stream_mem_new ();
+/**
+ * e_attachment_bar_get_selected:
+ * @bar: an #EAttachmentBar object
+ *
+ * Returns a newly allocated #GSList of ref'd #EAttachment objects
+ * representing the selected items in the #EAttachmentBar Icon List.
+ **/
+GSList *
+e_attachment_bar_get_selected (EAttachmentBar *bar)
+{
+	EAttachmentBarPrivate *priv;
+	GSList *attachments = NULL;
+	EAttachment *attachment;
+	GList *items;
+	int id;
 
-			camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
 
-			/* Stream image into pixbuf loader */
-			loader = gdk_pixbuf_loader_new ();
-			error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
-			gdk_pixbuf_loader_close (loader, NULL);
+	priv = bar->priv;
 
-			if (!error) {
-				pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-				attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-				pixbuf = attachment->pixbuf_cache;
-				g_object_ref (pixbuf);
-			} else {
-				pixbuf = NULL;
-				g_warning ("GdkPixbufLoader Error");
-			}
+	items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
 
-			/* Destroy everything */
-			g_object_unref (loader);
-			camel_object_unref (mstream);
-		} else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
-			attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-			pixbuf = attachment->pixbuf_cache;
-			g_object_ref (pixbuf);
+	while (items != NULL) {
+		if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
+			attachment = priv->attachments->pdata[id];
+			attachments = g_slist_prepend (attachments, attachment);
+			g_object_ref (attachment);
 		}
 
-		desc = camel_mime_part_get_description (attachment->body);
-		if (!desc || *desc == '\0') {
-			if (attachment->file_name)
-				desc = attachment->file_name;
-			else
-				desc = camel_mime_part_get_filename (attachment->body);
-		}
+		items = items->next;
+	}
 
-		if (!desc)
-			desc = _("attachment");
+	attachments = g_slist_reverse (attachments);
 
-		if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
-			label = g_strdup_printf ("%s (%s)", desc, size_string);
-			g_free (size_string);
-		} else
-			label = g_strdup (desc);
+	return attachments;
+}
 
-		if (pixbuf == NULL) {
-			char *mime_type;
+/* FIXME: Cleanup this, since there is a api to get selected attachments */
+/**
+ * e_attachment_bar_get_attachment:
+ * @bar: an #EAttachmentBar object
+ * @id: Index of the desired attachment or -1 to request all selected attachments
+ *
+ * Returns a newly allocated #GSList of ref'd #EAttachment objects
+ * representing the requested item(s) in the #EAttachmentBar Icon
+ * List.
+ **/
+GSList *
+e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
+{
+	EAttachmentBarPrivate *priv;
+	EAttachment *attachment;
+	GSList *attachments;
 
-			mime_type = camel_content_type_simple (content_type);
-			pixbuf = e_icon_for_mime_type (mime_type, 48);
-			if (pixbuf == NULL) {
-				g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
-				pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
-			}
-			g_free (mime_type);
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
 
-			/* remember this picture and use it later again */
-			if (pixbuf)
-				attachment->pixbuf_cache = g_object_ref (pixbuf);
-		}
+	priv = bar->priv;
 
-		if (pixbuf) {
-			GdkPixbuf *pixbuf_orig = pixbuf;
-			pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
-
-			/* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
-			   free the original one.
-			*/
-			g_object_unref (pixbuf_orig);
-
-			/* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
-			if (attachment->sign) {
-				/* Show the signature status at the right-bottom.*/
-				GdkPixbuf *sign = NULL;
-				int x, y;
-
-				if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
-					sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
-				else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
-					sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
-				else
-					sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
-
-				x = gdk_pixbuf_get_width (pixbuf) - 17;
-				y = gdk_pixbuf_get_height (pixbuf) - 17;
-
-				gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
-				g_object_unref (sign);
-			}
-
-			if (attachment->encrypt) {
-				/* Show the encryption status at the top left.*/
-				GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
-
-				gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
-				g_object_unref (encrypt);
-			}
-
-			gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
-			g_object_unref (pixbuf);
-		}
-
-		g_free (label);
-	}
-
-	gnome_icon_list_thaw (icon_list);
-
-	/* Resize */
-	if (bar->expand) {
-		gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
-
-		if (bar->priv->attachments->len) {
-			int per_col, rows, height, width;
-
-			calculate_height_width(bar, &width, &height);
-			per_col = bar_width / width;
-			per_col = (per_col ? per_col : 1);
-			rows = (bar->priv->attachments->len + per_col -1) / per_col;
-			gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
-		}
-	}
-}
-
-static void
-update_remote_file (EAttachment *attachment, EAttachmentBar *bar)
-{
-	GnomeIconList *icon_list;
-	GnomeIconTextItem *item;
-	char *msg, *base;
-
-	if (attachment->percentage == -1) {
-		update (bar);
-		return;
-	}
-
-	base = g_path_get_basename(attachment->file_name);
-	msg = g_strdup_printf("%s (%d%%)", base, attachment->percentage);
-	g_free(base);
-
-	icon_list = GNOME_ICON_LIST (bar);
-
-	gnome_icon_list_freeze (icon_list);
-
-	item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index);
-	if (!item->is_text_allocated)
-		g_free (item->text);
-
-	gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE);
-
-	gnome_icon_list_thaw (icon_list);
-}
-
-void
-e_attachment_bar_remove_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	int id, left, nrem = 0;
-	GList *items;
-	GPtrArray *temp_arr;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	priv = bar->priv;
-
-	if (!(items = gnome_icon_list_get_selection ((GnomeIconList *) bar)))
-		return;
-
-	temp_arr = g_ptr_array_new ();
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data) - nrem) < priv->attachments->len) {
-			attachment = E_ATTACHMENT(g_ptr_array_index (priv->attachments, id));
-			g_ptr_array_add (temp_arr, (gpointer)attachment);
-			g_ptr_array_remove_index (priv->attachments, id);
-			nrem++;
-		}
-
-		items = items->next;
-	}
-
-	g_ptr_array_foreach (temp_arr, (GFunc)g_object_unref, NULL);
-	g_ptr_array_free (temp_arr, TRUE);
-
-	update (bar);
-
-	g_signal_emit (bar, signals[CHANGED], 0);
-
-	id++;
-
-	if ((left = gnome_icon_list_get_num_icons ((GnomeIconList *) bar)) > 0)
-		gnome_icon_list_focus_icon ((GnomeIconList *) bar, left > id ? id : left - 1);
-}
-
-void
-e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
-{
-	int per_col, rows, height, width;
-
-	calculate_height_width(bar, &width, &height);
-	per_col = bar_width / width;
-	per_col = (per_col ? per_col : 1);
-	rows = (bar->priv->attachments->len + per_col - 1) / per_col;
-	gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height);
-}
-
-void
-e_attachment_bar_edit_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	GList *items;
-	int id;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	priv = bar->priv;
-
-	items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
-			attachment = priv->attachments->pdata[id];
-			e_attachment_edit (attachment, GTK_WIDGET (bar));
-		}
-
-		items = items->next;
-	}
-}
-
-GtkWidget **
-e_attachment_bar_get_selector(EAttachmentBar *bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	return &bar->priv->attach;
-}
-
-/**
- * e_attachment_bar_get_selected:
- * @bar: an #EAttachmentBar object
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the selected items in the #EAttachmentBar Icon List.
- **/
-GSList *
-e_attachment_bar_get_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	GSList *attachments = NULL;
-	EAttachment *attachment;
-	GList *items;
-	int id;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
-
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
-			attachment = priv->attachments->pdata[id];
-			attachments = g_slist_prepend (attachments, attachment);
-			g_object_ref (attachment);
-		}
-
-		items = items->next;
-	}
-
-	attachments = g_slist_reverse (attachments);
-
-	return attachments;
-}
-
-/* FIXME: Cleanup this, since there is a api to get selected attachments */
-/**
- * e_attachment_bar_get_attachment:
- * @bar: an #EAttachmentBar object
- * @id: Index of the desired attachment or -1 to request all selected attachments
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the requested item(s) in the #EAttachmentBar Icon
- * List.
- **/
-GSList *
-e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	GSList *attachments;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	if (id == -1 || id > priv->attachments->len)
-		return e_attachment_bar_get_selected (bar);
+	if (id == -1 || id > priv->attachments->len)
+		return e_attachment_bar_get_selected (bar);
 
 	attachment = priv->attachments->pdata[id];
 	attachments = g_slist_prepend (NULL, attachment);
@@ -724,7 +841,7 @@
 GSList *
 e_attachment_bar_get_all_attachments (EAttachmentBar *bar)
 {
-	struct _EAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 	GSList *attachments = NULL;
 	EAttachment *attachment;
 	int i;
@@ -748,7 +865,7 @@
 GSList *
 e_attachment_bar_get_parts (EAttachmentBar *bar)
 {
-	struct _EAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 	EAttachment *attachment;
 	GSList *parts = NULL;
 	int i;
@@ -758,50 +875,22 @@
 	priv = bar->priv;
 
 	for (i = 0; i < priv->attachments->len; i++) {
+		CamelMimePart *mime_part;
+
 		attachment = priv->attachments->pdata[i];
+		mime_part = e_attachment_get_mime_part (attachment);
+
 		if (attachment->is_available_local)
-			parts = g_slist_prepend (parts, attachment->body);
+			parts = g_slist_prepend (parts, mime_part);
 	}
 
         return parts;
 }
 
-/* GtkObject methods.  */
-
-static void
-destroy (GtkObject *object)
-{
-	EAttachmentBar *bar = (EAttachmentBar *) object;
-	struct _EAttachmentBarPrivate *priv = bar->priv;
-	EAttachment *attachment;
-	int i;
-
-	if ((priv = bar->priv)) {
-		priv->batch_unref = TRUE;
-		for (i = 0; i < priv->attachments->len; i++) {
-			attachment = priv->attachments->pdata[i];
-			g_object_weak_unref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-			g_object_unref (attachment);
-		}
-		g_ptr_array_free (priv->attachments, TRUE);
-
-		if (priv->attach)
-			gtk_widget_destroy (priv->attach);
-
-		if (priv->path)
-			g_free (priv->path);
-
-		g_free (priv);
-		bar->priv = NULL;
-	}
-
-	if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
-		(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-}
-
 static char *
-temp_save_part (CamelMimePart *part, gboolean readonly)
+temp_save_part (EAttachment *attachment, gboolean readonly)
 {
+	CamelMimePart *mime_part;
 	const char *filename;
 	char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL;
 	CamelStream *stream;
@@ -810,7 +899,9 @@
 	if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX")))
 		return NULL;
 
-	if (!(filename = camel_mime_part_get_filename (part))) {
+	mime_part = e_attachment_get_mime_part (attachment);
+
+	if (!(filename = camel_mime_part_get_filename (mime_part))) {
 		/* This is the default filename used for temporary file creation */
 		filename = _("Unknown");
 	} else {
@@ -825,7 +916,7 @@
 	g_free (tmpdir);
 	g_free (mfilename);
 
-	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 	if (readonly)
 		stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0444);
 	else
@@ -853,9 +944,344 @@
 }
 
 static void
-eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time)
+attachment_bar_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             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),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_bar_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             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,
+				e_attachment_bar_get_editable (
+				E_ATTACHMENT_BAR (object)));
+			return;
+
+		case PROP_UI_MANAGER:
+			g_value_set_object (
+				value,
+				e_attachment_bar_get_ui_manager (
+				E_ATTACHMENT_BAR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_bar_dispose (GObject *object)
+{
+	EAttachmentBarPrivate *priv;
+	guint ii;
+
+	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
+
+	priv->batch_unref = TRUE;
+
+	for (ii = 0; ii < priv->attachments->len; ii++) {
+		EAttachment *attachment;
+
+		attachment = priv->attachments->pdata[ii];
+		g_object_weak_unref (
+			G_OBJECT (attachment), (GWeakNotify)
+			attachment_destroy, object);
+		g_object_unref (attachment);
+	}
+	g_ptr_array_set_size (priv->attachments, 0);
+
+	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->open_actions != NULL) {
+		g_object_unref (priv->open_actions);
+		priv->open_actions = NULL;
+	}
+
+	/* Chain up to parent's dipose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_bar_finalize (GObject *object)
+{
+	EAttachmentBarPrivate *priv;
+
+	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);
+}
+
+static void
+attachment_bar_constructed (GObject *object)
+{
+	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
+attachment_bar_event (GtkWidget *widget,
+                      GdkEvent *event)
+{
+	EAttachment *attachment;
+	gboolean ret = FALSE;
+	gpointer parent;
+	CamelURL *url;
+	char *path;
+	GSList *p;
+
+	if (event->type != GDK_2BUTTON_PRESS)
+		return FALSE;
+
+	parent = gtk_widget_get_toplevel (widget);
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	p = e_attachment_bar_get_selected (E_ATTACHMENT_BAR (widget));
+	/* check if has body already, remote files can take longer to fetch */
+	if (p && p->next == NULL && e_attachment_get_mime_part (p->data) != NULL) {
+		attachment = p->data;
+
+		/* Check if the file is stored already */
+		if (!attachment->store_uri) {
+			path = temp_save_part (attachment, TRUE);
+			url = camel_url_new ("file://", NULL);
+			camel_url_set_path (url, path);
+			attachment->store_uri = camel_url_to_string (url, 0);
+			camel_url_free (url);
+			g_free (path);
+		}
+
+		e_show_uri (parent, attachment->store_uri);
+
+		ret = TRUE;
+	}
+
+	g_slist_foreach (p, (GFunc) g_object_unref, NULL);
+	g_slist_free (p);
+
+	return ret;
+}
+
+static gboolean
+attachment_bar_button_press_event (GtkWidget *widget,
+                                   GdkEventButton *event)
+{
+	GnomeIconList *icon_list;
+	GList *selected, *tmp;
+	int length, icon_number;
+	gboolean take_selected = FALSE;
+
+	GtkTargetEntry drag_types[] = {
+		{ "text/uri-list", 0, 0 },
+	};
+
+	icon_list = GNOME_ICON_LIST (widget);
+	selected = gnome_icon_list_get_selection (icon_list);
+	length = g_list_length (selected);
+
+	icon_number = gnome_icon_list_get_icon_at (
+		icon_list, event->x, event->y);
+	if (icon_number < 0) {
+		/* When nothing is selected, deselect all */
+		gnome_icon_list_unselect_all (icon_list);
+		length = 0;
+		selected = NULL;
+	}
+
+	if (event->button == 1) {
+		/* If something is selected, then allow drag or else help to select */
+		if (length)
+			gtk_drag_source_set (
+				widget, GDK_BUTTON1_MASK, drag_types,
+				G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
+		else
+			gtk_drag_source_unset (widget);
+		goto exit;
+	}
+
+	/* If not r-click dont progress any more.*/
+	if (event->button != 3)
+		goto exit;
+
+	/* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
+	 * or deselect all and select only this for r-click
+	 */
+	if (icon_number >= 0) {
+		for (tmp = selected; tmp; tmp = tmp->next) {
+			if (GPOINTER_TO_INT (tmp->data) == icon_number)
+				take_selected = TRUE;
+		}
+
+		if (!take_selected) {
+			gnome_icon_list_unselect_all (icon_list);
+			gnome_icon_list_select_icon (icon_list, icon_number);
+		}
+	}
+
+	attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), event);
+
+exit:
+	/* Chain up to parent's button_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		button_press_event (widget, event);
+}
+
+static gboolean
+attachment_bar_button_release_event (GtkWidget *widget,
+                                     GdkEventButton *event)
+{
+	GnomeIconList *icon_list;
+	GList *selected;
+
+	GtkTargetEntry drag_types[] = {
+		{ "text/uri-list", 0, 0 },
+	};
+
+	if (event->button != 1)
+		goto exit;
+
+	icon_list = GNOME_ICON_LIST (widget);
+	selected = gnome_icon_list_get_selection (icon_list);
+
+	if (selected != NULL)
+		gtk_drag_source_set (
+			widget, GDK_BUTTON1_MASK, drag_types,
+			G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
+	else
+		gtk_drag_source_unset (widget);
+
+exit:
+	/* Chain up to parent's button_release_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		button_release_event (widget, event);
+}
+
+static gboolean
+attachment_bar_key_press_event (GtkWidget *widget,
+                                GdkEventKey *event)
+{
+	EAttachmentBar *attachment_bar;
+	gboolean editable;
+
+	attachment_bar = E_ATTACHMENT_BAR (widget);
+	editable = e_attachment_bar_get_editable (attachment_bar);
+
+	if (editable && event->keyval == GDK_Delete) {
+		GtkActionGroup *action_group;
+		GtkAction *action;
+
+		action_group = attachment_bar->priv->editable_actions;
+		action = gtk_action_group_get_action (action_group, "remove");
+		gtk_action_activate (action);
+	}
+
+	/* Chain up to parent's key_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		key_press_event (widget, event);
+}
+
+static void
+attachment_bar_drag_data_get (GtkWidget *widget,
+                              GdkDragContext *drag,
+                              GtkSelectionData *data,
+                              guint info,
+                              guint time)
 {
-	struct _EAttachmentBarPrivate *priv = bar->priv;
+	EAttachmentBarPrivate *priv;
 	EAttachment *attachment;
 	char *path, **uris;
 	int len, n, i = 0;
@@ -865,7 +1291,8 @@
 	if (info)
 		return;
 
-	items = gnome_icon_list_get_selection (GNOME_ICON_LIST (bar));
+	priv = E_ATTACHMENT_BAR_GET_PRIVATE (widget);
+	items = gnome_icon_list_get_selection (GNOME_ICON_LIST (widget));
 	len = g_list_length (items);
 
 	uris = g_malloc0 (sizeof (char *) * (len + 1));
@@ -885,7 +1312,7 @@
 		}
 
 		/* If we are not able to save, ignore it */
-		if (!(path = temp_save_part (attachment->body, FALSE)))
+		if (!(path = temp_save_part (attachment, FALSE)))
 			continue;
 
 		url = camel_url_new ("file://", NULL);
@@ -902,227 +1329,280 @@
 	gtk_selection_data_set_uris (data, uris);
 
 	g_free (uris);
-
-	return;
 }
 
 static gboolean
-eab_button_release_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
+attachment_bar_popup_menu (GtkWidget *widget)
 {
-	GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
-	GList *selected;
-	int length;
-	GtkTargetEntry drag_types[] = {
-		{ "text/uri-list", 0, 0 },
-	};
-
-	if (event && event->button == 1) {
-		selected = gnome_icon_list_get_selection(icon_list);
-		length = g_list_length (selected);
-		if (length)
-			gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
-		else
-			gtk_drag_source_unset((GtkWidget *)bar);
-	}
+	attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), NULL);
 
-	return FALSE;
+	return TRUE;
 }
 
-static gboolean
-eab_button_press_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
+static void
+attachment_bar_update_actions (EAttachmentBar *attachment_bar)
 {
-	GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
-	GList *selected = NULL, *tmp;
-	int length, icon_number;
-	gboolean take_selected = FALSE;
-	GtkTargetEntry drag_types[] = {
-		{ "text/uri-list", 0, 0 },
-	};
-
-	selected = gnome_icon_list_get_selection(icon_list);
-	length = g_list_length (selected);
+	GnomeIconList *icon_list;
+	CamelMimePart *mime_part;
+	GtkUIManager *ui_manager;
+	GtkActionGroup *action_group;
+	GtkAction *action;
+	GList *selection;
+	guint n_selected;
+	gboolean is_image;
+	gpointer parent;
+	guint merge_id;
+
+	icon_list = GNOME_ICON_LIST (attachment_bar);
+	selection = gnome_icon_list_get_selection (icon_list);
+	n_selected = g_list_length (selection);
 
-	if (event) {
-		icon_number = gnome_icon_list_get_icon_at(icon_list, event->x, event->y);
-		if (icon_number < 0) {
-			/* When nothing is selected, deselect all */
-			gnome_icon_list_unselect_all (icon_list);
-			length = 0;
-			selected = NULL;
-		}
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 
-		if (event->button == 1) {
-			/* If something is selected, then allow drag or else help to select */
-			if (length)
-				gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
-			else
-				gtk_drag_source_unset((GtkWidget *)bar);
-			return FALSE;
-		}
+	is_image = FALSE;
+	mime_part = NULL;
 
-		/* If not r-click dont progress any more.*/
-		if (event->button != 3)
-			return FALSE;
-
-		/* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
-		 * or deselect all and select only this for r-click
-		 */
-		if (icon_number >= 0) {
-			for (tmp = selected; tmp; tmp = tmp->next) {
-				if (GPOINTER_TO_INT(tmp->data) == icon_number)
-					take_selected = TRUE;
-			}
+	if (n_selected == 1) {
+		GPtrArray *array;
+		EAttachment *attachment;
+		gint index;
 
-			if (!take_selected) {
-				gnome_icon_list_unselect_all(icon_list);
-				gnome_icon_list_select_icon(icon_list, icon_number);
-			}
-		}
+		array = attachment_bar->priv->attachments;
+		index = GPOINTER_TO_INT (selection->data);
+		attachment = E_ATTACHMENT (array->pdata[index]);
+		mime_part = e_attachment_get_mime_part (attachment);
+		is_image = e_attachment_is_image (attachment);
 	}
 
-	return FALSE;
-}
+	ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
 
-static gboolean
-eab_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, gpointer *dummy)
-{
-	EAttachment *attachment;
-	gboolean ret = FALSE;
-	CamelURL *url;
-	char *path;
-	GSList *p;
+	action_group = attachment_bar->priv->standard_actions;
 
-	if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) {
-		p = e_attachment_bar_get_selected (bar);
-		/* check if has body already, remote files can take longer to fetch */
-		if (p && p->next == NULL && ((EAttachment *)p->data)->body) {
-			attachment = p->data;
-
-			/* Check if the file is stored already */
-			if (!attachment->store_uri) {
-				path = temp_save_part (attachment->body, TRUE);
-				url = camel_url_new ("file://", NULL);
-				camel_url_set_path (url, path);
-				attachment->store_uri = camel_url_to_string (url, 0);
-				camel_url_free (url);
-				g_free (path);
-			}
+	action = gtk_action_group_get_action (action_group, "save-as");
+	gtk_action_set_visible (action, n_selected > 0);
 
-			/* FIXME Pass a parent window. */
-			e_show_uri (NULL, attachment->store_uri);
+	action = gtk_action_group_get_action (action_group, "set-background");
+	gtk_action_set_visible (action, is_image);
 
-			ret = TRUE;
-		}
+	action_group = attachment_bar->priv->editable_actions;
 
-		if (p) {
-			g_slist_foreach (p, (GFunc) g_object_unref, NULL);
-			g_slist_free (p);
-		}
-	}
+	action = gtk_action_group_get_action (action_group, "properties");
+	gtk_action_set_visible (action, n_selected == 1);
 
-	return ret;
-}
+	action = gtk_action_group_get_action (action_group, "remove");
+	gtk_action_set_visible (action, n_selected > 0);
 
-/* Initialization.  */
+	action_group = attachment_bar->priv->open_actions;
 
-static void
-class_init (EAttachmentBarClass *klass)
-{
-	GtkObjectClass *object_class;
+	merge_id = attachment_bar->priv->merge_id;
+	gtk_ui_manager_remove_ui (ui_manager, merge_id);
+	e_action_group_remove_all_actions (action_group);
 
-	object_class = GTK_OBJECT_CLASS (klass);
+	if (mime_part == NULL)
+		return;
 
-	parent_class = g_type_class_ref (gnome_icon_list_get_type ());
+	e_mime_part_utils_add_open_actions (
+		mime_part, ui_manager, action_group,
+		"/attachment-popup/open-actions", parent, merge_id);
+}
 
-	object_class->destroy = destroy;
+static void
+attachment_bar_class_init (EAttachmentBarClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
 
-	/* Setup signals.  */
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentBarPrivate));
 
-	signals[CHANGED] =
-		g_signal_new ("changed",
-			      E_TYPE_ATTACHMENT_BAR,
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EAttachmentBarClass, changed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_bar_set_property;
+	object_class->get_property = attachment_bar_get_property;
+	object_class->dispose = attachment_bar_dispose;
+	object_class->finalize = attachment_bar_finalize;
+	object_class->constructed = attachment_bar_constructed;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->event = attachment_bar_event;
+	widget_class->button_press_event = attachment_bar_button_press_event;
+	widget_class->button_release_event = attachment_bar_button_release_event;
+	widget_class->key_press_event = attachment_bar_key_press_event;
+	widget_class->drag_data_get = attachment_bar_drag_data_get;
+	widget_class->popup_menu = attachment_bar_popup_menu;
+
+	class->update_actions = attachment_bar_update_actions;
+
+	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",
+			"Editable",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_UI_MANAGER,
+		g_param_spec_object (
+			"ui-manager",
+			"UI Manager",
+			NULL,
+			GTK_TYPE_UI_MANAGER,
+			G_PARAM_READABLE));
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EAttachmentBarClass, changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[UPDATE_ACTIONS] = g_signal_new (
+		"update-actions",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		G_STRUCT_OFFSET (EAttachmentBarClass, update_actions),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
 }
 
 static void
-init (EAttachmentBar *bar)
+attachment_bar_init (EAttachmentBar *bar)
 {
-	struct _EAttachmentBarPrivate *priv;
+	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);
+	bar->priv->attachments = g_ptr_array_new ();
+
+	GTK_WIDGET_SET_FLAGS (bar, GTK_CAN_FOCUS);
 
-	priv = g_new (struct _EAttachmentBarPrivate, 1);
+	icon_list = GNOME_ICON_LIST (bar);
+
+	calculate_height_width (bar, &icon_width, &window_height);
+	gnome_icon_list_construct (icon_list, icon_width, NULL, 0);
 
-	priv->attach = NULL;
-	priv->batch_unref = FALSE;
-	priv->attachments = g_ptr_array_new ();
+	gtk_widget_set_size_request (
+		GTK_WIDGET (bar), icon_width * 4, window_height);
 
-	priv->path = NULL;
+	atk_object_set_name (
+		gtk_widget_get_accessible (GTK_WIDGET (bar)),
+		_("Attachment Bar"));
 
-	bar->priv = priv;
-	bar->expand = FALSE;
+	gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
+	gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
+	gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
+	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
 e_attachment_bar_get_type (void)
 {
 	static GType type = 0;
 
-	if (type == 0) {
-		static const GTypeInfo info = {
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
 			sizeof (EAttachmentBarClass),
-			NULL, NULL,
-			(GClassInitFunc) class_init,
-			NULL, NULL,
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_bar_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
 			sizeof (EAttachmentBar),
-			0,
-			(GInstanceInitFunc) init,
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_bar_init,
+			NULL   /* value_table */
 		};
 
-		type = g_type_register_static (GNOME_TYPE_ICON_LIST, "EAttachmentBar", &info, 0);
+		type = g_type_register_static (
+			GNOME_TYPE_ICON_LIST, "EAttachmentBar", &type_info, 0);
 	}
 
 	return type;
 }
 
-GtkWidget *
-e_attachment_bar_new (GtkAdjustment *adj)
-{
-	EAttachmentBar *new;
-	GnomeIconList *icon_list;
-	int icon_width, window_height;
-
-	new = g_object_new (e_attachment_bar_get_type (), NULL);
-
-	icon_list = GNOME_ICON_LIST (new);
-
-	calculate_height_width (new, &icon_width, &window_height);
-
-	gnome_icon_list_construct (icon_list, icon_width, adj, 0);
-
-	gtk_widget_set_size_request (GTK_WIDGET (new), icon_width * 4, window_height);
-
-        GTK_WIDGET_SET_FLAGS (new, GTK_CAN_FOCUS);
-
-	gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
-	gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
-	gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
-	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);
-
-	atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)),
-			     _("Attachment Bar"));
-
-	g_signal_connect (new, "button_release_event", G_CALLBACK(eab_button_release_event), NULL);
-	g_signal_connect (new, "button_press_event", G_CALLBACK(eab_button_press_event), NULL);
-	g_signal_connect (new, "drag-data-get", G_CALLBACK(eab_drag_data_get), NULL);
-	g_signal_connect (icon_list, "event", G_CALLBACK (eab_icon_clicked_cb), NULL);
-
-	return GTK_WIDGET (new);
+GtkWidget *
+e_attachment_bar_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT_BAR, NULL);
 }
 
 static char *
@@ -1159,12 +1639,14 @@
 {
 	CamelContentType *content_type;
 	CamelDataWrapper *content;
+	CamelMimePart *mime_part;
 
-	if (!attachment->body)
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part == NULL)
 		return;
 
-	content_type = camel_mime_part_get_content_type (attachment->body);
-	content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+	content_type = camel_mime_part_get_content_type (mime_part);
+	content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 
 	if (!CAMEL_IS_MULTIPART (content)) {
 		if (camel_content_type_is (content_type, "text", "*")) {
@@ -1188,7 +1670,7 @@
 			camel_object_unref (filter_stream);
 
 			encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT);
-			camel_mime_part_set_encoding (attachment->body, encoding);
+			camel_mime_part_set_encoding (mime_part, encoding);
 
 			if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
 				/* the text fits within us-ascii so this is safe */
@@ -1207,24 +1689,26 @@
 				/* looks kinda nasty, but this is how ya have to do it */
 				camel_content_type_set_param (content_type, "charset", default_charset);
 				type = camel_content_type_format (content_type);
-				camel_mime_part_set_content_type (attachment->body, type);
+				camel_mime_part_set_content_type (mime_part, type);
 				g_free (type);
 				g_free (buf);
 			}
 
 			camel_object_unref (bestenc);
 		} else if (!CAMEL_IS_MIME_MESSAGE (content)) {
-			camel_mime_part_set_encoding (attachment->body, CAMEL_TRANSFER_ENCODING_BASE64);
+			camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
 		}
 	}
 
-	camel_multipart_add_part (multipart, attachment->body);
+	camel_multipart_add_part (multipart, mime_part);
 }
 
 void
-e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, const char *default_charset)
+e_attachment_bar_to_multipart (EAttachmentBar *bar,
+                               CamelMultipart *multipart,
+                               const gchar *default_charset)
 {
-	struct _EAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 	EAttachment *attachment;
 	int i;
 
@@ -1249,32 +1733,73 @@
 }
 
 void
-e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition)
+e_attachment_bar_attach (EAttachmentBar *bar,
+                         const gchar *filename,
+                         const gchar *disposition)
 {
+	EAttachment *attachment;
+	CamelException ex;
+
 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-	g_return_if_fail (file_name != NULL && disposition != NULL);
+	g_return_if_fail (filename != NULL);
+	g_return_if_fail (disposition != NULL);
+
+	camel_exception_init (&ex);
+
+	attachment = e_attachment_new (filename, disposition, &ex);
 
-	add_from_file (bar, file_name, disposition);
+	if (attachment != NULL)
+		e_attachment_bar_add_attachment (bar, attachment);
+	else {
+		GtkWidget *toplevel;
+
+		/* FIXME: Avoid using error from mailer */
+		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (bar));
+		e_error_run (
+			GTK_WINDOW (toplevel), "mail-composer:no-attach",
+			filename, camel_exception_get_description (&ex), NULL);
+		camel_exception_clear (&ex);
+	}
 }
 
 void
-e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment)
+e_attachment_bar_add_attachment (EAttachmentBar *bar,
+                                 EAttachment *attachment)
 {
 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	g_ptr_array_add (bar->priv->attachments, attachment);
+
+	g_object_weak_ref (
+		G_OBJECT (attachment), (GWeakNotify)
+		attachment_destroy, bar);
+
+	g_signal_connect_swapped (
+		attachment, "changed",
+		G_CALLBACK (e_attachment_bar_refresh), bar);
+
+	e_attachment_bar_refresh (bar);
 
-	add_common (bar, attachment);
+	g_signal_emit (bar, signals[CHANGED], 0);
 }
 
 void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment)
+e_attachment_bar_add_attachment_silent (EAttachmentBar *bar,
+                                        EAttachment *attachment)
 {
 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-	g_return_if_fail (attachment != NULL);
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
 	g_ptr_array_add (bar->priv->attachments, attachment);
-	g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-	g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
 
+	g_object_weak_ref (
+		G_OBJECT (attachment), (GWeakNotify)
+		attachment_destroy, bar);
+
+	g_signal_connect_swapped (
+		attachment, "changed",
+		G_CALLBACK (e_attachment_bar_refresh), bar);
 
 	g_signal_emit (bar, signals[CHANGED], 0);
 }
@@ -1282,13 +1807,180 @@
 void
 e_attachment_bar_refresh (EAttachmentBar *bar)
 {
-	update (bar);
+	EAttachmentBarPrivate *priv;
+	GnomeIconList *icon_list;
+	int bar_width, bar_height;
+	int i;
+
+	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+
+	priv = bar->priv;
+	icon_list = GNOME_ICON_LIST (bar);
+
+	gnome_icon_list_freeze (icon_list);
+
+	gnome_icon_list_clear (icon_list);
+
+	/* FIXME could be faster, but we don't care.  */
+	for (i = 0; i < priv->attachments->len; i++) {
+		EAttachment *attachment;
+		CamelContentType *content_type;
+		CamelMimePart *mime_part;
+		char *size_string, *label;
+		GdkPixbuf *pixbuf = NULL;
+		const char *desc;
+
+		attachment = priv->attachments->pdata[i];
+		mime_part = e_attachment_get_mime_part (attachment);
+
+		if (!attachment->is_available_local || mime_part == NULL) {
+			if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
+				attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
+				g_object_unref (pixbuf);
+			}
+			continue;
+		}
+
+		content_type = camel_mime_part_get_content_type (mime_part);
+		/* Get the image out of the attachment
+		   and create a thumbnail for it */
+		pixbuf = e_attachment_get_thumbnail (attachment);
+		if (pixbuf != NULL)
+			g_object_ref (pixbuf);
+		else if (camel_content_type_is(content_type, "image", "*")) {
+			CamelDataWrapper *wrapper;
+			CamelStreamMem *mstream;
+			GdkPixbufLoader *loader;
+			gboolean error = TRUE;
+
+			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);
+
+			/* Stream image into pixbuf loader */
+			loader = gdk_pixbuf_loader_new ();
+			error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
+			gdk_pixbuf_loader_close (loader, NULL);
+
+			if (!error) {
+				/* The loader owns the reference. */
+				pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+				/* This returns a new GdkPixbuf. */
+				pixbuf = scale_pixbuf (pixbuf);
+				e_attachment_set_thumbnail (attachment, pixbuf);
+			} else {
+				pixbuf = NULL;
+				g_warning ("GdkPixbufLoader Error");
+			}
+
+			/* Destroy everything */
+			g_object_unref (loader);
+			camel_object_unref (mstream);
+		} else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
+			/* This returns a new GdkPixbuf. */
+			pixbuf = scale_pixbuf (pixbuf);
+			e_attachment_set_thumbnail (attachment, pixbuf);
+		}
+
+		desc = camel_mime_part_get_description (mime_part);
+		if (desc == NULL || *desc == '\0')
+			desc = e_attachment_get_filename (attachment);
+		if (desc == NULL || *desc == '\0')
+			desc = camel_mime_part_get_filename (mime_part);
+
+		if (!desc)
+			desc = _("attachment");
+
+		if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
+			label = g_strdup_printf ("%s (%s)", desc, size_string);
+			g_free (size_string);
+		} else
+			label = g_strdup (desc);
+
+		if (pixbuf == NULL) {
+			char *mime_type;
+
+			mime_type = camel_content_type_simple (content_type);
+			pixbuf = e_icon_for_mime_type (mime_type, 48);
+			if (pixbuf == NULL) {
+				g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
+				pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
+			}
+			g_free (mime_type);
+
+			/* remember this picture and use it later again */
+			if (pixbuf)
+				e_attachment_set_thumbnail (attachment, pixbuf);
+		}
+
+		if (pixbuf) {
+			GdkPixbuf *pixbuf_orig = pixbuf;
+			pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
+
+			/* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
+			   free the original one.
+			*/
+			g_object_unref (pixbuf_orig);
+
+			/* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
+			if (attachment->sign) {
+				/* Show the signature status at the right-bottom.*/
+				GdkPixbuf *sign = NULL;
+				int x, y;
+
+				if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
+					sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
+				else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
+					sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
+				else
+					sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
+
+				x = gdk_pixbuf_get_width (pixbuf) - 17;
+				y = gdk_pixbuf_get_height (pixbuf) - 17;
+
+				gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
+				g_object_unref (sign);
+			}
+
+			if (attachment->encrypt) {
+				/* Show the encryption status at the top left.*/
+				GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
+
+				gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
+				g_object_unref (encrypt);
+			}
+
+			gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
+			g_object_unref (pixbuf);
+		}
+
+		g_free (label);
+	}
+
+	gnome_icon_list_thaw (icon_list);
+
+	/* Resize */
+	if (bar->expand) {
+		gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
+
+		if (bar->priv->attachments->len) {
+			int per_col, rows, height, width;
+
+			calculate_height_width(bar, &width, &height);
+			per_col = bar_width / width;
+			per_col = (per_col ? per_col : 1);
+			rows = (bar->priv->attachments->len + per_col -1) / per_col;
+			gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
+		}
+	}
 }
 
 int
 e_attachment_bar_get_download_count (EAttachmentBar *bar)
 {
-	struct _EAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 	EAttachment *attachment;
 	int i, n = 0;
 
@@ -1306,68 +1998,57 @@
 }
 
 void
-e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition)
+e_attachment_bar_attach_remote_file (EAttachmentBar *bar,
+                                     const gchar *url,
+                                     const gchar *disposition)
 {
 	EAttachment *attachment;
 	CamelException ex;
-	GtkWindow *parent;
+	GtkWidget *parent;
 
 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
 
-	if (!bar->priv->path)
+	if (bar->priv->path == NULL)
 		bar->priv->path = e_mkdtemp ("attach-XXXXXX");
 
-	parent = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar);
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (bar));
 	camel_exception_init (&ex);
-	if ((attachment = e_attachment_new_remote_file (parent, url, disposition, bar->priv->path, &ex))) {
-		add_common (bar, attachment);
-		g_signal_connect (attachment, "update", G_CALLBACK (update_remote_file), bar);
+
+	attachment = e_attachment_new_remote_file (
+		GTK_WINDOW (parent), url, disposition, bar->priv->path, &ex);
+
+	if (attachment != NULL) {
+		e_attachment_bar_add_attachment (bar, attachment);
+		g_signal_connect (
+			attachment, "update",
+			G_CALLBACK (update_remote_file), bar);
 	} else {
-		e_error_run (parent, "mail-composer:no-attach",
-			     url, camel_exception_get_description (&ex), NULL);
+		e_error_run (
+			GTK_WINDOW (parent), "mail-composer:no-attach",
+			url, camel_exception_get_description (&ex), NULL);
 		camel_exception_clear (&ex);
 	}
 }
 
 void
-e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part)
-{
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	add_from_mime_part (bar, part);
-}
-
-static void
-action_recent_cb (GtkAction *action, 
-		  EAttachmentBar *attachment_bar)
+e_attachment_bar_attach_mime_part (EAttachmentBar *bar,
+                                   CamelMimePart *part)
 {
-	GtkRecentChooser *chooser;
-	GFile *file;
-	gchar *uri;
-
-	chooser = GTK_RECENT_CHOOSER (action);
+	EAttachment *attachment;
 
-	/* 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);
+	/* XXX Is this function really worth keeping? */
 
-	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_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+	g_return_if_fail (CAMEL_IS_MIME_PART (part));
 
-	g_object_unref (file);
+	attachment = e_attachment_new_from_mime_part (part);
+	e_attachment_bar_add_attachment (bar, attachment);
 }
 
 GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar, 
-				const gchar *action_name,
-				const gchar *action_label)
+e_attachment_bar_recent_action_new (EAttachmentBar *bar,
+                                    const gchar *action_name,
+                                    const gchar *action_label)
 {
 	GtkAction *action;
 	GtkRecentChooser *chooser;
@@ -1392,3 +2073,148 @@
 	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)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+	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)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), FALSE);
+
+	return attachment_bar->priv->editable;
+}
+
+void
+e_attachment_bar_set_editable (EAttachmentBar *attachment_bar,
+                               gboolean editable)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+	attachment_bar->priv->editable = editable;
+
+	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;
+}

Modified: branches/kill-bonobo/widgets/misc/e-attachment-bar.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-bar.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-bar.h	Mon Mar  9 03:31:24 2009
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef __E_ATTACHMENT_BAR_H__
-#define __E_ATTACHMENT_BAR_H__
+#ifndef E_ATTACHMENT_BAR_H
+#define E_ATTACHMENT_BAR_H
 
 #include <gtk/gtk.h>
 #include <libgnomeui/gnome-icon-list.h>
@@ -30,70 +30,107 @@
 #include <camel/camel-multipart.h>
 #include "e-attachment.h"
 
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
 #define E_TYPE_ATTACHMENT_BAR \
 	(e_attachment_bar_get_type ())
 #define E_ATTACHMENT_BAR(obj) \
-	(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
-#define E_ATTACHMENT_BAR_CLASS(klass) \
-	(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
+#define E_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
 #define E_IS_ATTACHMENT_BAR(obj) \
-	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-#define E_IS_ATTACHMENT_BAR_CLASS(klass) \
-	(G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_BAR))
+#define E_IS_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_BAR))
+#define E_ATTACHMENT_BAR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+
+G_BEGIN_DECLS
 
 typedef struct _EAttachmentBar EAttachmentBar;
 typedef struct _EAttachmentBarClass EAttachmentBarClass;
+typedef struct _EAttachmentBarPrivate EAttachmentBarPrivate;
 
 struct _EAttachmentBar {
 	GnomeIconList parent;
 	gboolean expand;
-
-	struct _EAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 };
 
 struct _EAttachmentBarClass {
 	GnomeIconListClass parent_class;
 
-	void (* changed) (EAttachmentBar *bar);
+	/* Signals */
+	void		(*changed)		(EAttachmentBar *bar);
+	void		(*update_actions)	(EAttachmentBar *bar);
 };
 
+GType		e_attachment_bar_get_type	(void);
+GtkWidget *	e_attachment_bar_new		(void);
+void		e_attachment_bar_to_multipart	(EAttachmentBar *bar,
+						 CamelMultipart *multipart,
+						 const gchar *default_charset);
+guint		e_attachment_bar_get_num_attachments
+						(EAttachmentBar *bar);
+void		e_attachment_bar_attach		(EAttachmentBar *bar,
+						 const gchar *filename,
+						 const gchar *disposition);
+void		e_attachment_bar_attach_mime_part
+						(EAttachmentBar *bar,
+						 CamelMimePart *part);
+gint		e_attachment_bar_get_download_count
+						(EAttachmentBar *bar);
+void		e_attachment_bar_attach_remote_file
+						(EAttachmentBar *bar,
+						 const gchar *url,
+						 const gchar *disposition);
+GSList *	e_attachment_bar_get_attachment	(EAttachmentBar *bar,
+						 gint id);
+void		e_attachment_bar_add_attachment	(EAttachmentBar *bar,
+						 EAttachment *attachment);
+GSList *	e_attachment_bar_get_parts	(EAttachmentBar *bar);
+GSList *	e_attachment_bar_get_selected	(EAttachmentBar *bar);
+void		e_attachment_bar_set_width	(EAttachmentBar *bar,
+						 gint bar_width);
+GSList *	e_attachment_bar_get_all_attachments
+						(EAttachmentBar *bar);
+void		e_attachment_bar_create_attachment_cache
+						(EAttachment *attachment);
+GtkAction *	e_attachment_bar_recent_action_new
+						(EAttachmentBar *bar, 
+						 const gchar *action_name,
+						 const gchar *action_label);
+void		e_attachment_bar_add_attachment_silent
+						(EAttachmentBar *bar,
+						 EAttachment *attachment);
+void		e_attachment_bar_refresh	(EAttachmentBar *bar);
+gint		e_attachment_bar_file_chooser_dialog_run
+						(EAttachmentBar *attachment_bar,
+						 GtkWidget *dialog);
+void		e_attachment_bar_update_actions	(EAttachmentBar *attachment_bar);
+const gchar *	e_attachment_bar_get_background_filename
+						(EAttachmentBar *attachment_bar);
+void		e_attachment_bar_set_background_filename
+						(EAttachmentBar *attachment_bar,
+						 const gchar *background_filename);
+const gchar *	e_attachment_bar_get_background_options
+						(EAttachmentBar *attachment_bar);
+void		e_attachment_bar_set_background_options
+						(EAttachmentBar *attachment_bar,
+						 const gchar *background_options);
+const gchar *	e_attachment_bar_get_current_folder
+						(EAttachmentBar *attachment_bar);
+void		e_attachment_bar_set_current_folder
+						(EAttachmentBar *attachment_bar,
+						 const gchar *current_folder);
+gboolean	e_attachment_bar_get_editable	(EAttachmentBar *attachment_bar);
+void		e_attachment_bar_set_editable	(EAttachmentBar *attachment_bar,
+						 gboolean editable);
+GtkUIManager *	e_attachment_bar_get_ui_manager	(EAttachmentBar *attachment_bar);
 
-GType e_attachment_bar_get_type (void);
-
-GtkWidget *e_attachment_bar_new (GtkAdjustment *adj);
-void e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart,
-				    const char *default_charset);
-guint e_attachment_bar_get_num_attachments (EAttachmentBar *bar);
-void e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition);
-void e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part);
-int e_attachment_bar_get_download_count (EAttachmentBar *bar);
-void e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition);
-GSList *e_attachment_bar_get_attachment (EAttachmentBar *bar, int id);
-void e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment);
-void e_attachment_bar_edit_selected (EAttachmentBar *bar);
-void e_attachment_bar_remove_selected (EAttachmentBar *bar);
-GtkWidget ** e_attachment_bar_get_selector(EAttachmentBar *bar);
-GSList *e_attachment_bar_get_parts (EAttachmentBar *bar);
-GSList *e_attachment_bar_get_selected (EAttachmentBar *bar);
-void e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width);
-GSList * e_attachment_bar_get_all_attachments (EAttachmentBar *bar);
-void e_attachment_bar_create_attachment_cache (EAttachment *attachment);
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar, 
-				const gchar *action_name,
-				const gchar *action_label);
-void 
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment);
-void 
-e_attachment_bar_refresh (EAttachmentBar *bar);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+G_END_DECLS
 
-#endif /* __E_ATTACHMENT_BAR_H__ */
+#endif /* E_ATTACHMENT_BAR_H */

Added: branches/kill-bonobo/widgets/misc/e-attachment-dialog.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-dialog.c	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,413 @@
+/*
+ * e-attachment-dialog.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-dialog.h"
+
+#include <glib/gi18n.h>
+
+#define E_ATTACHMENT_DIALOG_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogPrivate))
+
+struct _EAttachmentDialogPrivate {
+	EAttachment *attachment;
+	GtkWidget *filename_entry;
+	GtkWidget *description_entry;
+	GtkWidget *mime_type_label;
+	GtkWidget *disposition_checkbox;
+};
+
+enum {
+	PROP_0,
+	PROP_ATTACHMENT
+};
+
+static gpointer parent_class;
+
+static void
+attachment_dialog_update (EAttachmentDialog *dialog)
+{
+	EAttachment *attachment;
+	CamelMimePart *mime_part;
+	GtkWidget *widget;
+	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);
+	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;
+	gtk_widget_set_sensitive (widget, sensitive);
+	gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+	text = NULL;
+	if (attachment != NULL)
+		text = e_attachment_get_description (attachment);
+	text = (text != NULL) ? text : "";
+	widget = dialog->priv->description_entry;
+	gtk_widget_set_sensitive (widget, sensitive);
+	gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+	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);
+	widget = dialog->priv->disposition_checkbox;
+	gtk_widget_set_sensitive (widget, sensitive);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+}
+
+static void
+attachment_dialog_set_property (GObject *object,
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ATTACHMENT:
+			e_attachment_dialog_set_attachment (
+				E_ATTACHMENT_DIALOG (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_dialog_get_property (GObject *object,
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ATTACHMENT:
+			g_value_set_object (
+				value, e_attachment_dialog_get_attachment (
+				E_ATTACHMENT_DIALOG (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_dialog_dispose (GObject *object)
+{
+	EAttachmentDialogPrivate *priv;
+
+	priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (object);
+
+	if (priv->attachment != NULL) {
+		g_object_unref (priv->attachment);
+		priv->attachment = NULL;
+	}
+
+	if (priv->filename_entry != NULL) {
+		g_object_unref (priv->filename_entry);
+		priv->filename_entry = NULL;
+	}
+
+	if (priv->description_entry != NULL) {
+		g_object_unref (priv->description_entry);
+		priv->description_entry = NULL;
+	}
+
+	if (priv->mime_type_label != NULL) {
+		g_object_unref (priv->mime_type_label);
+		priv->mime_type_label = NULL;
+	}
+
+	if (priv->disposition_checkbox != NULL) {
+		g_object_unref (priv->disposition_checkbox);
+		priv->disposition_checkbox = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_dialog_map (GtkWidget *widget)
+{
+	GtkWidget *action_area;
+	GtkWidget *content_area;
+
+	/* Chain up to parent's map() method. */
+	GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+	/* XXX Override GtkDialog's broken style property defaults. */
+	action_area = gtk_dialog_get_action_area (GTK_DIALOG (widget));
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (widget));
+
+	gtk_box_set_spacing (GTK_BOX (content_area), 12);
+	gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
+	gtk_container_set_border_width (GTK_CONTAINER (content_area), 12);
+}
+
+static void
+attachment_dialog_response (GtkDialog *dialog,
+                            gint response_id)
+{
+	EAttachmentDialogPrivate *priv;
+	EAttachment *attachment;
+	GtkToggleButton *button;
+	GtkEntry *entry;
+	const gchar *text;
+	gboolean active;
+
+	if (response_id != GTK_RESPONSE_OK)
+		return;
+
+	priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
+	g_return_if_fail (priv->attachment != NULL);
+	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);
+
+	button = GTK_TOGGLE_BUTTON (priv->disposition_checkbox);
+	active = gtk_toggle_button_get_active (button);
+	text = active ? "inline" : "attachment";
+	e_attachment_set_disposition (attachment, text);
+}
+
+static void
+attachment_dialog_class_init (EAttachmentDialogClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+	GtkDialogClass *dialog_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentDialogPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_dialog_set_property;
+	object_class->get_property = attachment_dialog_get_property;
+	object_class->dispose = attachment_dialog_dispose;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->map = attachment_dialog_map;
+
+	dialog_class = GTK_DIALOG_CLASS (class);
+	dialog_class->response = attachment_dialog_response;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ATTACHMENT,
+		g_param_spec_object (
+			"attachment",
+			"Attachment",
+			NULL,
+			E_TYPE_ATTACHMENT,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_dialog_init (EAttachmentDialog *dialog)
+{
+	GtkWidget *container;
+	GtkWidget *widget;
+
+	dialog->priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
+
+	gtk_dialog_add_button (
+		GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+	gtk_dialog_add_button (
+		GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
+	gtk_window_set_icon_name (
+		GTK_WINDOW (dialog), "mail-attachment");
+	gtk_window_set_title (
+		GTK_WINDOW (dialog), _("Attachment Properties"));
+
+	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+	widget = gtk_table_new (4, 2, FALSE);
+	gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
+	gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_entry_new ();
+	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+	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);
+	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_table_attach (
+		GTK_TABLE (container), widget,
+		0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_widget_show (widget);
+
+	widget = gtk_entry_new ();
+	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	dialog->priv->description_entry = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_label_new_with_mnemonic (_("_Description:"));
+	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+	gtk_label_set_mnemonic_widget (
+		GTK_LABEL (widget), dialog->priv->description_entry);
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+	gtk_widget_show (widget);
+
+	widget = gtk_label_new (NULL);
+	gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+	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);
+	gtk_widget_show (widget);
+
+	widget = gtk_label_new (_("MIME Type:"));
+	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+	gtk_widget_show (widget);
+
+	widget = gtk_check_button_new_with_mnemonic (
+		_("_Suggest automatic display of attachment"));
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		0, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	dialog->priv->disposition_checkbox = g_object_ref (widget);
+	gtk_widget_show (widget);
+}
+
+GType
+e_attachment_dialog_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EAttachmentDialogClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_dialog_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_init */
+			sizeof (EAttachmentDialog),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_dialog_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_DIALOG, "EAttachmentDialog", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_attachment_dialog_new (GtkWindow *parent,
+                         EAttachment *attachment)
+{
+	if (parent != NULL)
+	 	g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
+	if (attachment != NULL)
+		g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return g_object_new (
+		E_TYPE_ATTACHMENT_DIALOG,
+		"transient-for", parent, "attachment", attachment, NULL);
+}
+
+EAttachment *
+e_attachment_dialog_get_attachment (EAttachmentDialog *dialog)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT_DIALOG (dialog), NULL);
+
+	return dialog->priv->attachment;
+}
+
+void
+e_attachment_dialog_set_attachment (EAttachmentDialog *dialog,
+                                    EAttachment *attachment)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_DIALOG (dialog));
+
+	if (attachment != NULL) {
+		g_return_if_fail (E_IS_ATTACHMENT (attachment));
+		g_object_ref (attachment);
+	}
+
+	if (dialog->priv->attachment != NULL)
+		g_object_unref (dialog->priv->attachment);
+
+	dialog->priv->attachment = attachment;
+
+	attachment_dialog_update (dialog);
+
+	g_object_notify (G_OBJECT (dialog), "attachment");
+}

Added: branches/kill-bonobo/widgets/misc/e-attachment-dialog.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-attachment-dialog.h	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,73 @@
+/*
+ * e-attachment-dialog.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_DIALOG_H
+#define E_ATTACHMENT_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_DIALOG \
+	(e_attachment_dialog_get_type ())
+#define E_ATTACHMENT_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialog))
+#define E_ATTACHMENT_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogClass))
+#define E_IS_ATTACHMENT_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_DIALOG))
+#define E_IS_ATTACHMENT_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_DIALOG))
+#define E_ATTACHMENT_DIALOG_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentDialog EAttachmentDialog;
+typedef struct _EAttachmentDialogClass EAttachmentDialogClass;
+typedef struct _EAttachmentDialogPrivate EAttachmentDialogPrivate;
+
+struct _EAttachmentDialog {
+	GtkDialog parent;
+	EAttachmentDialogPrivate *priv;
+};
+
+struct _EAttachmentDialogClass {
+	GtkDialogClass parent_class;
+};
+
+GType		e_attachment_dialog_get_type	(void);
+GtkWidget *	e_attachment_dialog_new		(GtkWindow *parent,
+						 EAttachment *attachment);
+EAttachment *	e_attachment_dialog_get_attachment
+						(EAttachmentDialog *dialog);
+void		e_attachment_dialog_set_attachment
+						(EAttachmentDialog *dialog,
+						 EAttachment *attachment);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_DIALOG_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	Mon Mar  9 03:31:24 2009
@@ -27,6 +27,9 @@
 #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.
@@ -56,7 +59,27 @@
 #include "e-util/e-mktemp.h"
 #include "e-util/e-util-private.h"
 
-#include "e-attachment.h"
+#define E_ATTACHMENT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
+
+struct _EAttachmentPrivate {
+	gchar *filename;
+	gchar *description;
+	gchar *disposition;
+	gchar *mime_type;
+
+	GdkPixbuf *thumbnail;
+	CamelMimePart *mime_part;
+};
+
+enum {
+	PROP_0,
+	PROP_DESCRIPTION,
+	PROP_DISPOSITION,
+	PROP_FILENAME,
+	PROP_THUMBNAIL
+};
 
 enum {
 	CHANGED,
@@ -64,112 +87,207 @@
 	LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static GObjectClass *parent_class = NULL;
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
 
 static void
-changed (EAttachment *attachment)
+attachment_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
 {
-	g_signal_emit (attachment, signals[CHANGED], 0);
-}
+	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;
 
-/* GtkObject methods.  */
+		case PROP_FILENAME:
+			e_attachment_set_filename (
+				E_ATTACHMENT (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_THUMBNAIL:
+			e_attachment_set_thumbnail (
+				E_ATTACHMENT (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
 
 static void
-finalise (GObject *object)
+attachment_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
 {
-	EAttachment *attachment = (EAttachment *) object;
-	GtkWidget *dialog;
+	switch (property_id) {
+		case PROP_DESCRIPTION:
+			g_value_set_string (
+				value, e_attachment_get_description (
+				E_ATTACHMENT (object)));
+			return;
 
-	if (attachment->editor_gui != NULL) {
-		dialog = glade_xml_get_widget (attachment->editor_gui, "dialog");
-		g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_CLOSE);
-	}
+		case PROP_DISPOSITION:
+			g_value_set_string (
+				value, e_attachment_get_disposition (
+				E_ATTACHMENT (object)));
+			return;
 
-	if (attachment->is_available_local) {
-		camel_object_unref (attachment->body);
-		if (attachment->pixbuf_cache != NULL)
-			g_object_unref (attachment->pixbuf_cache);
-	} else {
-		if (attachment->cancellable) {
-			/* the operation is still running, so cancel it */
-			g_cancellable_cancel (attachment->cancellable);
-			attachment->cancellable = NULL;
-		}
-		g_free (attachment->description);
-	}
+		case PROP_FILENAME:
+			g_value_set_string (
+				value, e_attachment_get_filename (
+				E_ATTACHMENT (object)));
+			return;
 
-	g_free (attachment->file_name);
-	g_free (attachment->store_uri);
+		case PROP_THUMBNAIL:
+			g_value_set_object (
+				value, e_attachment_get_thumbnail (
+				E_ATTACHMENT (object)));
+			return;
+	}
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-
-/* Signals.  */
-
 static void
-real_changed (EAttachment *attachment)
+attachment_dispose (GObject *object)
 {
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	EAttachmentPrivate *priv;
+
+	priv = E_ATTACHMENT_GET_PRIVATE (object);
+
+	if (priv->thumbnail != NULL) {
+		g_object_unref (priv->thumbnail);
+		priv->thumbnail = NULL;
+	}
+
+	if (priv->mime_part != NULL) {
+		camel_object_unref (priv->mime_part);
+		priv->mime_part = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
-real_update_attachment (EAttachment *attachment, char *msg)
+attachment_finalize (GObject *object)
 {
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
-}
+	EAttachment *attachment = (EAttachment *) object;
+
+	if (attachment->cancellable) {
+		/* the operation is still running, so cancel it */
+		g_cancellable_cancel (attachment->cancellable);
+		attachment->cancellable = NULL;
+	}
+
+	g_free (attachment->store_uri);
 
+	g_free (attachment->priv->filename);
+	g_free (attachment->priv->description);
+	g_free (attachment->priv->disposition);
+	g_free (attachment->priv->mime_type);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
 
 static void
-class_init (EAttachmentClass *klass)
+attachment_class_init (EAttachmentClass *class)
 {
 	GObjectClass *object_class;
 
-	object_class = (GObjectClass*) klass;
-	parent_class = g_type_class_ref (G_TYPE_OBJECT);
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_set_property;
+	object_class->get_property = attachment_get_property;
+	object_class->dispose = attachment_dispose;
+	object_class->finalize = attachment_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DESCRIPTION,
+		g_param_spec_string (
+			"description",
+			"Description",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
 
-	object_class->finalize = finalise;
-	klass->changed = real_changed;
-	klass->update = real_update_attachment;
-
-	signals[CHANGED] = g_signal_new ("changed",
-					 E_TYPE_ATTACHMENT,
-					 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",
-					 E_TYPE_ATTACHMENT,
-					 G_SIGNAL_RUN_FIRST,
-					 G_STRUCT_OFFSET (EAttachmentClass, update),
-					 NULL,
-					 NULL,
-					 g_cclosure_marshal_VOID__VOID,
-					 G_TYPE_NONE, 0);
+	g_object_class_install_property (
+		object_class,
+		PROP_DESCRIPTION,
+		g_param_spec_string (
+			"disposition",
+			"Disposition",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
 
+	g_object_class_install_property (
+		object_class,
+		PROP_DESCRIPTION,
+		g_param_spec_string (
+			"filename",
+			"Filename",
+			NULL,
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_THUMBNAIL,
+		g_param_spec_object (
+			"thumbnail",
+			"Thumbnail Image",
+			NULL,
+			GDK_TYPE_PIXBUF,
+			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
-init (EAttachment *attachment)
+attachment_init (EAttachment *attachment)
 {
-	attachment->editor_gui = NULL;
-	attachment->body = NULL;
-	attachment->size = 0;
-	attachment->pixbuf_cache = NULL;
+	attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
+
 	attachment->index = -1;
-	attachment->file_name = NULL;
 	attachment->percentage = -1;
-	attachment->description = NULL;
-	attachment->disposition = FALSE;
 	attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
 	attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
-	attachment->store_uri = NULL;
-	attachment->cancellable = NULL;
 }
 
 GType
@@ -177,20 +295,22 @@
 {
 	static GType type = 0;
 
-	if (type == 0) {
-		static const GTypeInfo info = {
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
 			sizeof (EAttachmentClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) class_init,
-			NULL,
-			NULL,
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
 			sizeof (EAttachment),
-			0,
-			(GInstanceInitFunc) init,
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_init,
+			NULL   /* value_table */
 		};
 
-		type = g_type_register_static (G_TYPE_OBJECT, "EAttachment", &info, 0);
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EAttachment", &type_info, 0);
 	}
 
 	return type;
@@ -198,42 +318,42 @@
 
 /**
  * file_ext_is:
- * @param file_name: path for file
+ * @param filename: path for file
  * @param ext: desired extension, with a dot
- * @return if file_name has extension ext or not
+ * @return if filename has extension ext or not
  **/
 
 static gboolean
-file_ext_is (const char *file_name, const char *ext)
+file_ext_is (const char *filename, const char *ext)
 {
 	int i, dot = -1;
 
-	if (!file_name || !ext)
+	if (!filename || !ext)
 		return FALSE;
 
-	for (i = 0; file_name[i]; i++) {
-		if (file_name [i] == '.')
+	for (i = 0; filename[i]; i++) {
+		if (filename [i] == '.')
 			dot = i;
 	}
 
 	if (dot > 0) {
-		return 0 == g_ascii_strcasecmp (file_name + dot, ext);
+		return 0 == g_ascii_strcasecmp (filename + dot, ext);
 	}
 
 	return FALSE;
 }
 
 static char *
-attachment_guess_mime_type (const char *file_name)
+attachment_guess_mime_type (const char *filename)
 {
 	char *type;
 	gchar *content = NULL;
 
-	type = e_util_guess_mime_type (file_name, TRUE);
+	type = e_util_guess_mime_type (filename, TRUE);
 
 	if (type && strcmp (type, "text/directory") == 0 &&
-	    file_ext_is (file_name, ".vcf") &&
-	    g_file_get_contents (file_name, &content, NULL, NULL) &&
+	    file_ext_is (filename, ".vcf") &&
+	    g_file_get_contents (filename, &content, NULL, NULL) &&
 	    content) {
 		EVCard *vc = e_vcard_new_from_string (content);
 
@@ -265,30 +385,30 @@
 
 /**
  * e_attachment_new:
- * @file_name: filename to attach
+ * @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 *file_name, const char *disposition, CamelException *ex)
+e_attachment_new (const char *filename, const char *disposition, CamelException *ex)
 {
 	EAttachment *new;
 	CamelMimePart *part;
 	CamelDataWrapper *wrapper;
 	CamelStream *stream;
 	struct stat statbuf;
-	char *mime_type;
-	char *filename;
+	gchar *mime_type;
+	gchar *basename;
 	CamelURL *url;
 
-	g_return_val_if_fail (file_name != NULL, NULL);
+	g_return_val_if_fail (filename != NULL, NULL);
 
-	if (g_stat (file_name, &statbuf) < 0) {
+	if (g_stat (filename, &statbuf) < 0) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+				      filename, g_strerror (errno));
 		return NULL;
 	}
 
@@ -296,18 +416,18 @@
 	if (!S_ISREG (statbuf.st_mode)) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: not a regular file"),
-				      file_name);
+				      filename);
 		return NULL;
 	}
 
-	if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
+	if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+				      filename, g_strerror (errno));
 		return NULL;
 	}
 
-	if ((mime_type = attachment_guess_mime_type (file_name))) {
+	if ((mime_type = attachment_guess_mime_type (filename))) {
 		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
 			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
 		} else {
@@ -330,8 +450,8 @@
 	camel_object_unref (wrapper);
 
 	camel_mime_part_set_disposition (part, disposition);
-	filename = g_path_get_basename (file_name);
-	camel_mime_part_set_filename (part, filename);
+	basename = g_path_get_basename (filename);
+	camel_mime_part_set_filename (part, basename);
 
 #if 0
 	/* Note: Outlook 2002 is broken with respect to Content-Ids on
@@ -344,17 +464,15 @@
 	g_free (content_id);
 #endif
 
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
-	new->body = 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;
-	new->file_name = filename;
 
 	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, file_name);
+	camel_url_set_path (url, filename);
 	new->store_uri = camel_url_to_string (url, 0);
 	camel_url_free (url);
 
@@ -364,7 +482,7 @@
 
 typedef struct {
 	EAttachment *attachment;
-	char *file_name;
+	char *filename;
 	char *uri;
 	GtkWindow *parent; /* for error dialog */
 
@@ -394,7 +512,7 @@
 	if (download_info->cancellable)
 		g_object_unref (download_info->cancellable);
 
-	g_free (download_info->file_name);
+	g_free (download_info->filename);
 	g_free (download_info->uri);
 	g_free (download_info->buffer);
 	g_free (download_info);
@@ -450,7 +568,7 @@
 		download_info->attachment->cancellable = NULL;
 
 		camel_exception_init (&ex);
-		e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
+		e_attachment_build_remote_file (download_info->filename, download_info->attachment, &ex);
 
 		if (camel_exception_is_set (&ex)) {
 			download_info->was_error = TRUE;
@@ -482,7 +600,7 @@
 {
 	GError *error = NULL;
 	GFile *src = g_file_new_for_uri (download_info->uri);
-	GFile *des = g_file_new_for_path (download_info->file_name);
+	GFile *des = g_file_new_for_path (download_info->filename);
 	gboolean res = FALSE;
 
 	g_return_val_if_fail (src != NULL && des != NULL, FALSE);
@@ -538,6 +656,7 @@
 	DownloadInfo *download_info;
 	CamelURL *url;
 	char *base;
+	gchar *filename;
 
 	g_return_val_if_fail (uri != NULL, NULL);
 
@@ -545,25 +664,26 @@
 	base = g_path_get_basename (url->path);
 	camel_url_free (url);
 
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
-	new->body = NULL;
+	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;
-	new->file_name = g_build_filename (path, base, NULL);
 
 	g_free (base);
 
 	download_info = g_new0 (DownloadInfo, 1);
 	download_info->attachment = new;
-	download_info->file_name = g_strdup (new->file_name);
+	download_info->filename = g_strdup (filename);
 	download_info->uri = g_strdup (uri);
 	download_info->parent = error_dlg_parent;
 	download_info->was_error = FALSE;
 
+	g_free (filename);
+
 	/* it frees all on the error, so do not free it twice */
 	if (!download_to_local_path (download_info, ex))
 		return NULL;
@@ -573,23 +693,27 @@
 
 
 void
-e_attachment_build_remote_file (const char *file_name, EAttachment *attachment, const char *disposition, CamelException *ex)
+e_attachment_build_remote_file (const gchar *filename,
+                                EAttachment *attachment,
+                                CamelException *ex)
 {
 	CamelMimePart *part;
 	CamelDataWrapper *wrapper;
 	CamelStream *stream;
 	struct stat statbuf;
-	char *mime_type;
-	char *filename;
+	const gchar *description;
+	const gchar *disposition;
+	gchar *mime_type;
+	gchar *basename;
 	CamelURL *url;
 
-	g_return_if_fail (file_name != NULL);
+	g_return_if_fail (filename != NULL);
 
-	if (g_stat (file_name, &statbuf) == -1) {
+	if (g_stat (filename, &statbuf) == -1) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
-		g_message ("Cannot attach file %s: %s\n", file_name, g_strerror (errno));
+				      filename, g_strerror (errno));
+		g_message ("Cannot attach file %s: %s\n", filename, g_strerror (errno));
 		return;
 	}
 
@@ -597,19 +721,19 @@
 	if (!S_ISREG (statbuf.st_mode)) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: not a regular file"),
-				      file_name);
-		g_message ("Cannot attach file %s: not a regular file", file_name);
+				      filename);
+		g_message ("Cannot attach file %s: not a regular file", filename);
 		return;
 	}
 
-	if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
+	if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+				      filename, g_strerror (errno));
 		return;
 	}
 
-	if ((mime_type = attachment_guess_mime_type (file_name))) {
+	if ((mime_type = attachment_guess_mime_type (filename))) {
 		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
 			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
 		} else {
@@ -631,36 +755,34 @@
 	camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
 	camel_object_unref (wrapper);
 
-	if (attachment->disposition)
-		camel_mime_part_set_disposition (part, "inline");
-	else
-		camel_mime_part_set_disposition (part, "attachment");
+	disposition = e_attachment_get_disposition (attachment);
+	camel_mime_part_set_disposition (part, disposition);
 
-	if (!attachment->file_name)
-		filename = g_path_get_basename (file_name);
+	if (e_attachment_get_filename (attachment) == NULL)
+		basename = g_path_get_basename (filename);
 	else
-		filename = g_path_get_basename (attachment->file_name);
+		basename = g_path_get_basename (e_attachment_get_filename (attachment));
 
 	camel_mime_part_set_filename (part, filename);
 
-	if (attachment->description) {
-		camel_mime_part_set_description (part, attachment->description);
-		g_free (attachment->description);
-		attachment->description = NULL;
+	description = e_attachment_get_description (attachment);
+	if (description != NULL) {
+		camel_mime_part_set_description (part, description);
+		e_attachment_set_description (attachment, NULL);
 	}
 
-	attachment->editor_gui = NULL;
-	attachment->body = part;
+	attachment->priv->mime_part = part;
 	attachment->size = statbuf.st_size;
 	attachment->guessed_type = TRUE;
-	g_free (attachment->file_name);
-	attachment->file_name = filename;
+
+	e_attachment_set_filename (attachment, basename);
 
 	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, file_name);
+	camel_url_set_path (url, filename);
 	attachment->store_uri = camel_url_to_string (url, 0);
 	camel_url_free (url);
 
+	g_free (basename);
 }
 
 
@@ -674,210 +796,231 @@
 e_attachment_new_from_mime_part (CamelMimePart *part)
 {
 	EAttachment *new;
+	const gchar *filename;
 
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
 
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
+	filename = camel_mime_part_get_filename (part);
+
+	new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
 	camel_object_ref (part);
-	new->body = part;
+	new->priv->mime_part = part;
 	new->guessed_type = FALSE;
 	new->is_available_local = TRUE;
 	new->size = camel_mime_part_get_content_size (part);
-	new->file_name = g_strdup (camel_mime_part_get_filename(part));
 
 	return new;
 }
 
-
-/* The attachment property dialog.  */
-
-typedef struct {
+void
+e_attachment_edit (EAttachment *attachment,
+                   GtkWindow *parent)
+{
 	GtkWidget *dialog;
-	GtkEntry *file_name_entry;
-	GtkEntry *description_entry;
-	GtkEntry *mime_type_entry;
-	GtkToggleButton *disposition_checkbox;
-	EAttachment *attachment;
-} DialogData;
 
-static void
-destroy_dialog_data (DialogData *data)
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	dialog = e_attachment_dialog_new (parent, attachment);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+}
+
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
 {
-	g_free (data);
+	CamelMimePart *mime_part;
+	const gchar *description;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	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;
 }
 
-/*
- * fixme: I am converting EVERYTHING to/from UTF-8, although mime types
- * are in ASCII. This is not strictly necessary, but we want to be
- * consistent and possibly check for errors somewhere.
- */
+void
+e_attachment_set_description (EAttachment *attachment,
+                              const gchar *description)
+{
+	CamelMimePart *mime_part;
 
-static void
-set_entry (GladeXML *xml, const char *widget_name, const char *value)
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	g_free (attachment->priv->description);
+	attachment->priv->description = g_strdup (description);
+
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part != NULL)
+		camel_mime_part_set_description (mime_part, description);
+
+	g_object_notify (G_OBJECT (attachment), "description");
+}
+
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
 {
-	GtkEntry *entry;
+	CamelMimePart *mime_part;
+	const gchar *disposition;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name));
-	if (entry == NULL)
-		g_warning ("Entry for `%s' not found.", widget_name);
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part != NULL)
+		disposition = camel_mime_part_get_disposition (mime_part);
 	else
-		gtk_entry_set_text (entry, value ? value : "");
+		disposition = attachment->priv->disposition;
+
+	return disposition;
 }
 
-static void
-connect_widget (GladeXML *gui, const char *name, const char *signal_name,
-		GCallback func, gpointer data)
+void
+e_attachment_set_disposition (EAttachment *attachment,
+                              const gchar *disposition)
 {
-	GtkWidget *widget;
+	CamelMimePart *mime_part;
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	g_free (attachment->priv->disposition);
+	attachment->priv->disposition = g_strdup (disposition);
+
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part != NULL)
+		camel_mime_part_set_disposition (mime_part, disposition);
 
-	widget = glade_xml_get_widget (gui, name);
-	g_signal_connect (widget, signal_name, func, data);
+	g_object_notify (G_OBJECT (attachment), "disposition");
 }
 
-static void
-close_cb (GtkWidget *widget, gpointer data)
+const gchar *
+e_attachment_get_filename (EAttachment *attachment)
 {
-	EAttachment *attachment;
-	DialogData *dialog_data;
+	CamelMimePart *mime_part;
+	const gchar *filename;
 
-	dialog_data = (DialogData *) data;
-	attachment = dialog_data->attachment;
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	gtk_widget_destroy (dialog_data->dialog);
-	g_object_unref (attachment->editor_gui);
-	attachment->editor_gui = NULL;
+	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;
 
-	destroy_dialog_data (dialog_data);
+	return filename;
 }
 
-static void
-ok_cb (GtkWidget *widget, gpointer data)
+void
+e_attachment_set_filename (EAttachment *attachment,
+                           const gchar *filename)
 {
-	DialogData *dialog_data;
-	EAttachment *attachment;
-	const char *str;
+	CamelMimePart *mime_part;
 
-	dialog_data = (DialogData *) data;
-	attachment = dialog_data->attachment;
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 
-	str = gtk_entry_get_text (dialog_data->file_name_entry);
-	if (attachment->is_available_local)
-		camel_mime_part_set_filename (attachment->body, str);
-	g_free (attachment->file_name);
-	attachment->file_name = g_strdup (str);
-
-	str = gtk_entry_get_text (dialog_data->description_entry);
-	if (attachment->is_available_local) {
-		camel_mime_part_set_description (attachment->body, str);
-	} else {
-		g_free (attachment->description);
-		attachment->description = g_strdup (str);
-	}
+	g_free (attachment->priv->filename);
+	attachment->priv->filename = g_strdup (filename);
 
-	str = gtk_entry_get_text (dialog_data->mime_type_entry);
-	if (attachment->is_available_local) {
-		camel_mime_part_set_content_type (attachment->body, str);
-		camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str);
-	}
-
-	if (attachment->is_available_local) {
-		switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) {
-		case 0:
-			camel_mime_part_set_disposition (attachment->body, "attachment");
-			break;
-		case 1:
-			camel_mime_part_set_disposition (attachment->body, "inline");
-			break;
-		default:
-			/* Hmmmm? */
-			break;
-		}
-	} else {
-		attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox);
-	}
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part != NULL)
+		camel_mime_part_set_filename (mime_part, filename);
 
-	changed (attachment);
-	close_cb (widget, data);
+	g_object_notify (G_OBJECT (attachment), "filename");
 }
 
-static void
-response_cb (GtkWidget *widget, gint response, gpointer data)
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
 {
-	if (response == GTK_RESPONSE_OK)
-		ok_cb (widget, data);
-	else
-		close_cb (widget, data);
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->mime_part;
 }
 
-void
-e_attachment_edit (EAttachment *attachment, GtkWidget *parent)
+const gchar *
+e_attachment_get_mime_type (EAttachment *attachment)
 {
 	CamelContentType *content_type;
-	const char *disposition;
-	DialogData *dialog_data;
-	GladeXML *editor_gui;
-	GtkWidget *window;
-	char *type;
-	char *filename;
+	CamelMimePart *mime_part;
+	const gchar *filename;
+	gchar *mime_type;
 
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-	if (attachment->editor_gui != NULL) {
-		window = glade_xml_get_widget (attachment->editor_gui, "dialog");
-		gdk_window_show (window->window);
-		return;
-	}
+	if (attachment->priv->mime_type != NULL)
+		goto exit;
 
-	filename = g_build_filename (EVOLUTION_GLADEDIR, "e-attachment.glade", NULL);
-	editor_gui = glade_xml_new (filename, NULL, NULL);
-	g_free (filename);
+	mime_part = e_attachment_get_mime_part (attachment);
+	filename = e_attachment_get_filename (attachment);
+	content_type = camel_mime_part_get_content_type (mime_part);
 
-	if (editor_gui == NULL) {
-		g_warning ("Cannot load `e-attachment.glade'");
-		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);
 	}
 
-	attachment->editor_gui = editor_gui;
+	attachment->priv->mime_type = mime_type;
 
-	gtk_window_set_transient_for (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")),
-				      GTK_WINDOW (gtk_widget_get_toplevel (parent)));
+exit:
+	return attachment->priv->mime_type;
+}
 
-	dialog_data = g_new (DialogData, 1);
-	dialog_data->attachment = attachment;
-	dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog");
-	dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "file_name_entry"));
-	dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "description_entry"));
-	dialog_data->mime_type_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "mime_type_entry"));
-	dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON (glade_xml_get_widget (editor_gui, "disposition_checkbox"));
-
-	if (attachment->is_available_local && attachment->body) {
-		set_entry (editor_gui, "file_name_entry", camel_mime_part_get_filename (attachment->body));
-		set_entry (editor_gui, "description_entry", camel_mime_part_get_description (attachment->body));
-		content_type = camel_mime_part_get_content_type (attachment->body);
-		type = camel_content_type_simple (content_type);
-		set_entry (editor_gui, "mime_type_entry", type);
-		g_free (type);
-
-		disposition = camel_mime_part_get_disposition (attachment->body);
-		gtk_toggle_button_set_active (dialog_data->disposition_checkbox,
-					      disposition && !g_ascii_strcasecmp (disposition, "inline"));
-	} else {
-		set_entry (editor_gui, "file_name_entry", attachment->file_name);
-		set_entry (editor_gui, "description_entry", attachment->description);
-		if ((type = attachment_guess_mime_type (attachment->file_name))) {
-			set_entry (editor_gui, "mime_type_entry", type);
-			g_free (type);
-		} else {
-			set_entry (editor_gui, "mime_type_entry", "");
-		}
+GdkPixbuf *
+e_attachment_get_thumbnail (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
 
-		gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition);
+	return attachment->priv->thumbnail;
+}
+
+void
+e_attachment_set_thumbnail (EAttachment *attachment,
+                            GdkPixbuf *thumbnail)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	if (thumbnail != NULL) {
+		g_return_if_fail (GDK_IS_PIXBUF (thumbnail));
+		g_object_ref (thumbnail);
 	}
 
-	connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data);
+	if (attachment->priv->thumbnail != NULL)
+		g_object_unref (attachment->priv->thumbnail);
+
+	attachment->priv->thumbnail = thumbnail;
+
+	g_object_notify (G_OBJECT (attachment), "thumbnail");
+}
+
+gboolean
+e_attachment_is_image (EAttachment *attachment)
+{
+	CamelContentType *content_type;
+	CamelMimePart *mime_part;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part == NULL)
+		return FALSE;
+
+	content_type = camel_mime_part_get_content_type (mime_part);
+
+	return camel_content_type_is (content_type, "image", "*");
+}
+
+gboolean
+e_attachment_is_inline (EAttachment *attachment)
+{
+	const gchar *disposition;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	disposition = e_attachment_get_disposition (attachment);
+	g_return_val_if_fail (disposition != NULL, FALSE);
 
-	/* make sure that when the parent gets hidden/closed that our windows also close */
-	parent = gtk_widget_get_toplevel (parent);
-	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_data->dialog), TRUE);
+	return (g_ascii_strcasecmp (disposition, "inline") == 0);
 }

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	Mon Mar  9 03:31:24 2009
@@ -15,14 +15,14 @@
  *
  * Authors:
  *		Ettore Perazzoli <ettore ximian com>
- * 	   	Srinivasa Ragavan <sragavan novell com>
+ *		Srinivasa Ragavan <sragavan novell com>
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
 
-#ifndef __E_ATTACHMENT_H__
-#define __E_ATTACHMENT_H__
+#ifndef E_ATTACHMENT_H
+#define E_ATTACHMENT_H
 
 #include <gio/gio.h>
 #include <gtk/gtk.h>
@@ -31,73 +31,91 @@
 #include <camel/camel-exception.h>
 #include <camel/camel-cipher-context.h>
 
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT				(e_attachment_get_type ())
-#define E_ATTACHMENT(obj)				(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT, EAttachment))
-#define E_ATTACHMENT_CLASS(klass)			(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT, EAttachmentClass))
-#define E_IS_ATTACHMENT(obj)				(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT))
-#define E_IS_ATTACHMENT_CLASS(klass)			(G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT))
-
-
-typedef struct _EAttachment       EAttachment;
-typedef struct _EAttachmentClass  EAttachmentClass;
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT \
+	(e_attachment_get_type ())
+#define E_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT, EAttachment))
+#define E_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT, EAttachmentClass))
+#define E_IS_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT))
+#define E_IS_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((obj), E_TYPE_ATTACHMENT))
+#define E_ATTACHMENT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachment EAttachment;
+typedef struct _EAttachmentClass EAttachmentClass;
+typedef struct _EAttachmentPrivate EAttachmentPrivate;
 
 struct _EAttachment {
 	GObject parent;
 
-	GladeXML *editor_gui;
-
-	CamelMimePart *body;
 	gboolean guessed_type;
 	gulong size;
 
-	GdkPixbuf *pixbuf_cache;
-
 	GCancellable *cancellable;
 
 	gboolean is_available_local;
 	int percentage;
-	char *file_name;
-	char *description;
-	gboolean disposition;
 	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, char *msg);
+	void		(*changed)		(EAttachment *attachment);
+	void		(*update)		(EAttachment *attachment,
+						 gchar *message);
 };
 
-GType e_attachment_get_type (void);
-EAttachment *e_attachment_new (const char *file_name,
-			       const char *disposition,
-			       CamelException *ex);
-EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
-					    const char *url,
-			       		    const char *disposition,
-					    const char *path,
-	  	   			    CamelException *ex);
-void e_attachment_build_remote_file (const char *filename,
-				     EAttachment *attachment,
-		 	   	     const char *disposition,
-				     CamelException *ex);
-EAttachment *e_attachment_new_from_mime_part (CamelMimePart *part);
-void e_attachment_edit (EAttachment *attachment,
-			GtkWidget *parent);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+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);
+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);
+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);
+gboolean	e_attachment_is_image		(EAttachment *attachment);
+gboolean	e_attachment_is_inline		(EAttachment *attachment);
+
+G_END_DECLS
 
-#endif /* __E_ATTACHMENT_H__ */
+#endif /* E_ATTACHMENT_H */

Added: branches/kill-bonobo/widgets/misc/e-mime-part-utils.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-mime-part-utils.c	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,223 @@
+/*
+ * e-mime-part-utils.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-mime-part-utils.h"
+
+#include <errno.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <camel/camel-stream-vfs.h>
+
+#include "e-util/e-util.h"
+
+static void
+mime_part_utils_open_in_cb (GtkAction *action,
+                            CamelMimePart *mime_part)
+{
+	GtkWindow *parent;
+	GFile *file;
+	gchar *path;
+	gchar *uri;
+	gint fd;
+	GError *error = NULL;
+
+	parent = g_object_get_data (G_OBJECT (action), "parent-window");
+
+	fd = e_file_open_tmp (&path, &error);
+	if (error != NULL)
+		goto fail;
+
+	close (fd);
+
+	file = g_file_new_for_path (path);
+	e_mime_part_utils_save_to_file (mime_part, file, &error);
+	g_free (path);
+
+	if (error != NULL) {
+		g_object_unref (file);
+		goto fail;
+	}
+
+	uri = g_file_get_uri (file);
+	e_show_uri (parent, uri);
+	g_free (uri);
+
+	g_object_unref (file);
+
+	return;
+
+fail:
+	g_warning ("%s", error->message);
+	g_error_free (error);
+}
+
+GList *
+e_mime_part_utils_get_apps (CamelMimePart *mime_part)
+{
+	GList *app_info_list;
+	const gchar *filename;
+	gchar *content_type;
+	gchar *mime_type;
+	gchar *cp;
+
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
+
+	filename = camel_mime_part_get_filename (mime_part);
+	mime_type = camel_content_type_simple (
+		camel_mime_part_get_content_type (mime_part));
+	g_return_val_if_fail (mime_type != NULL, NULL);
+
+	/* GIO expects lowercase MIME types. */
+	for (cp = mime_type; *cp != '\0'; cp++)
+		*cp = g_ascii_tolower (*cp);
+
+	content_type = g_content_type_from_mime_type (mime_type);
+	if (content_type != NULL)
+		app_info_list = g_app_info_get_all_for_type (content_type);
+	else
+		app_info_list = g_app_info_get_all_for_type (mime_type);
+	g_free (content_type);
+
+	if (app_info_list != NULL || filename == NULL)
+		goto exit;
+
+	if (strcmp (mime_type, "application/octet-stream") != 0)
+		goto exit;
+
+	content_type = g_content_type_guess (filename, NULL, 0, NULL);
+	app_info_list = g_app_info_get_all_for_type (content_type);
+	g_free (content_type);
+
+exit:
+	g_free (mime_type);
+
+	return app_info_list;
+}
+
+gboolean
+e_mime_part_utils_save_to_file (CamelMimePart *mime_part,
+                                GFile *file,
+                                GError **error)
+{
+	GFileOutputStream *output_stream;
+	CamelDataWrapper *content;
+	CamelStream *stream;
+
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), FALSE);
+	g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+	output_stream = g_file_replace (
+		file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
+	if (output_stream == NULL)
+		return FALSE;
+
+	/* The CamelStream takes ownership of the GFileOutputStream. */
+	content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+	stream = camel_stream_vfs_new_with_stream (G_OBJECT (output_stream));
+
+	/* XXX Camel's streams are synchronous only, so we have to write
+	 *     the whole thing in one shot and hope it doesn't block the
+	 *     main loop for too long. */
+	if (camel_data_wrapper_decode_to_stream (content, stream) < 0)
+		goto file_error;
+
+	if (camel_stream_flush (stream) < 0)
+		goto file_error;
+
+	camel_object_unref (stream);
+
+	return TRUE;
+
+file_error:
+	g_set_error (
+		error, G_FILE_ERROR,
+		g_file_error_from_errno (errno),
+		"%s", g_strerror (errno));
+
+	camel_object_unref (stream);
+
+	return FALSE;
+}
+
+void
+e_mime_part_utils_add_open_actions (CamelMimePart *mime_part,
+                                    GtkUIManager *ui_manager,
+                                    GtkActionGroup *action_group,
+                                    const gchar *widget_path,
+                                    GtkWindow *parent,
+                                    guint merge_id)
+{
+	GList *app_info_list;
+	GList *iter;
+
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+	g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager));
+	g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
+	g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+	g_return_if_fail (widget_path != NULL);
+
+	app_info_list = e_mime_part_utils_get_apps (mime_part);
+
+	for (iter = app_info_list; iter != NULL; iter = iter->next) {
+		GAppInfo *app_info = iter->data;
+		GtkAction *action;
+		const gchar *app_executable;
+		const gchar *app_name;
+		gchar *action_tooltip;
+		gchar *action_label;
+		gchar *action_name;
+
+		if (!g_app_info_should_show (app_info))
+			continue;
+
+		app_executable = g_app_info_get_executable (app_info);
+		app_name = g_app_info_get_name (app_info);
+
+		action_name = g_strdup_printf ("open-in-%s", app_executable);
+		action_label = g_strdup_printf (_("Open in %s..."), app_name);
+
+		action_tooltip = g_strdup_printf (
+			_("Open this attachment in %s"), app_name);
+
+		action = gtk_action_new (
+			action_name, action_label, action_tooltip, NULL);
+
+		g_object_set_data (
+			G_OBJECT (action), "parent-window", parent);
+
+		g_signal_connect (
+			action, "activate",
+			G_CALLBACK (mime_part_utils_open_in_cb), mime_part);
+
+		gtk_action_group_add_action (action_group, action);
+
+		gtk_ui_manager_add_ui (
+			ui_manager, merge_id, widget_path, action_name,
+			action_name, GTK_UI_MANAGER_AUTO, FALSE);
+
+		g_free (action_name);
+		g_free (action_label);
+		g_free (action_tooltip);
+	}
+
+	g_list_foreach (app_info_list, (GFunc) g_object_unref, NULL);
+	g_list_free (app_info_list);
+}

Added: branches/kill-bonobo/widgets/misc/e-mime-part-utils.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-mime-part-utils.h	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,46 @@
+/*
+ * e-mime-part-utils.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_MIME_PART_UTILS_H
+#define E_MIME_PART_UTILS_H
+
+#include <gtk/gtk.h>
+#include <camel/camel-mime-part.h>
+#include <shell/e-shell-window.h>
+
+G_BEGIN_DECLS
+
+GList *		e_mime_part_utils_get_apps	(CamelMimePart *mime_part);
+gboolean	e_mime_part_utils_save_to_file	(CamelMimePart *mime_part,
+						 GFile *file,
+						 GError **error);
+
+void		e_mime_part_utils_add_open_actions
+						(CamelMimePart *mime_part,
+						 GtkUIManager *ui_manager,
+						 GtkActionGroup *action_group,
+						 const gchar *widget_path,
+						 GtkWindow *parent,
+						 guint merge_id);
+
+G_END_DECLS
+
+#endif /* E_MIME_PART_UTILS_H */

Added: branches/kill-bonobo/widgets/misc/e-timeout-activity.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-timeout-activity.c	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,180 @@
+/*
+ * e-timeout-activity.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-timeout-activity.h"
+
+#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
+
+struct _ETimeoutActivityPrivate {
+	guint timeout_id;
+};
+
+enum {
+	TIMEOUT,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static gulong signals[LAST_SIGNAL];
+
+static gboolean
+timeout_activity_cb (ETimeoutActivity *timeout_activity)
+{
+	g_signal_emit (timeout_activity, signals[TIMEOUT], 0);
+
+	return FALSE;
+}
+
+static void
+timeout_activity_finalize (GObject *object)
+{
+	ETimeoutActivityPrivate *priv;
+
+	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (object);
+
+	if (priv->timeout_id > 0)
+		g_source_remove (priv->timeout_id);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+timeout_activity_cancelled (EActivity *activity)
+{
+	ETimeoutActivityPrivate *priv;
+
+	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+	if (priv->timeout_id > 0) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	/* Chain up to parent's cancelled() method. */
+	E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
+}
+
+static void
+timeout_activity_completed (EActivity *activity)
+{
+	ETimeoutActivityPrivate *priv;
+
+	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+	if (priv->timeout_id > 0) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	/* Chain up to parent's completed() method. */
+	E_ACTIVITY_CLASS (parent_class)->completed (activity);
+}
+
+static void
+timeout_activity_timeout (ETimeoutActivity *timeout_activity)
+{
+	/* Allow subclasses to safely chain up. */
+}
+
+static void
+timeout_activity_class_init (ETimeoutActivityClass *class)
+{
+	GObjectClass *object_class;
+	EActivityClass *activity_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (ETimeoutActivityPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = timeout_activity_finalize;
+
+	activity_class = E_ACTIVITY_CLASS (class);
+	activity_class->cancelled = timeout_activity_cancelled;
+	activity_class->completed = timeout_activity_completed;
+
+	class->timeout = timeout_activity_timeout;
+
+	signals[TIMEOUT] = g_signal_new (
+		"timeout",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_FIRST,
+		G_STRUCT_OFFSET (ETimeoutActivityClass, timeout),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+timeout_activity_init (ETimeoutActivity *timeout_activity)
+{
+	timeout_activity->priv =
+		E_TIMEOUT_ACTIVITY_GET_PRIVATE (timeout_activity);
+}
+
+GType
+e_timeout_activity_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (ETimeoutActivityClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) timeout_activity_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (ETimeoutActivity),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) timeout_activity_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_ACTIVITY, "ETimeoutActivity", &type_info, 0);
+	}
+
+	return type;
+}
+
+EActivity *
+e_timeout_activity_new (const gchar *primary_text)
+{
+	return g_object_new (
+		E_TYPE_TIMEOUT_ACTIVITY,
+		"primary-text", primary_text, NULL);
+}
+
+void
+e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
+                                guint seconds)
+{
+	g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity));
+
+	if (timeout_activity->priv->timeout_id > 0)
+		e_activity_cancel (E_ACTIVITY (timeout_activity));
+
+	timeout_activity->priv->timeout_id = g_timeout_add_seconds (
+		seconds, (GSourceFunc) timeout_activity_cb, timeout_activity);
+}

Added: branches/kill-bonobo/widgets/misc/e-timeout-activity.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/widgets/misc/e-timeout-activity.h	Mon Mar  9 03:31:24 2009
@@ -0,0 +1,71 @@
+/*
+ * e-timeout-activity.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_TIMEOUT_ACTIVITY_H
+#define E_TIMEOUT_ACTIVITY_H
+
+#include <e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TIMEOUT_ACTIVITY \
+	(e_timeout_activity_get_type ())
+#define E_TIMEOUT_ACTIVITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivity))
+#define E_TIMEOUT_ACTIVITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+#define E_IS_TIMEOUT_ACTIVITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_IS_TIMEOUT_ACTIVITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_TIMEOUT_ACTIVITY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETimeoutActivity ETimeoutActivity;
+typedef struct _ETimeoutActivityClass ETimeoutActivityClass;
+typedef struct _ETimeoutActivityPrivate ETimeoutActivityPrivate;
+
+struct _ETimeoutActivity {
+	EActivity parent;
+	ETimeoutActivityPrivate *priv;
+};
+
+struct _ETimeoutActivityClass {
+	EActivityClass parent_class;
+
+	/* Signals */
+	void		(*timeout)	(ETimeoutActivity *timeout_activity);
+};
+
+GType		e_timeout_activity_get_type	(void);
+EActivity *	e_timeout_activity_new		(const gchar *primary_text);
+void		e_timeout_activity_set_timeout	(ETimeoutActivity *timeout_activity,
+						 guint seconds);
+
+G_END_DECLS
+
+#endif /* E_TIMEOUT_ACTIVITY_H */



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