aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--a11y/e-table/Makefile.am5
-rw-r--r--calendar/gui/dialogs/comp-editor.c860
-rw-r--r--calendar/gui/e-cal-popup.c442
-rw-r--r--composer/e-composer-actions.c72
-rw-r--r--composer/e-composer-private.c90
-rw-r--r--composer/e-composer-private.h13
-rw-r--r--composer/e-msg-composer.c545
-rw-r--r--composer/e-msg-composer.h14
-rw-r--r--e-util/Makefile.am2
-rw-r--r--e-util/e-util.c37
-rw-r--r--e-util/e-util.h9
-rw-r--r--mail/e-mail-browser.c2
-rw-r--r--mail/e-mail-reader.c2
-rw-r--r--mail/em-format-html-display.c136
-rw-r--r--mail/em-format-html-display.h2
-rw-r--r--mail/em-popup.c12
-rw-r--r--plugins/attachment-reminder/attachment-reminder.c11
-rw-r--r--plugins/import-ics-attachments/icsimporter.c1
-rw-r--r--shell/e-shell.c14
-rw-r--r--shell/main.c16
-rw-r--r--widgets/misc/Makefile.am12
-rw-r--r--widgets/misc/e-activity.c112
-rw-r--r--widgets/misc/e-activity.h8
-rw-r--r--widgets/misc/e-attachment-bar.c445
-rw-r--r--widgets/misc/e-attachment-dialog.c112
-rw-r--r--widgets/misc/e-attachment-icon-view.c319
-rw-r--r--widgets/misc/e-attachment-icon-view.h66
-rw-r--r--widgets/misc/e-attachment-paned.c563
-rw-r--r--widgets/misc/e-attachment-paned.h79
-rw-r--r--widgets/misc/e-attachment-store.c1073
-rw-r--r--widgets/misc/e-attachment-store.h110
-rw-r--r--widgets/misc/e-attachment-tree-view.c396
-rw-r--r--widgets/misc/e-attachment-tree-view.h66
-rw-r--r--widgets/misc/e-attachment-view.c1041
-rw-r--r--widgets/misc/e-attachment-view.h163
-rw-r--r--widgets/misc/e-attachment.c1584
-rw-r--r--widgets/misc/e-attachment.h98
-rw-r--r--widgets/misc/e-file-activity.c133
-rw-r--r--widgets/misc/e-file-activity.h10
-rw-r--r--widgets/misc/e-timeout-activity.c18
-rw-r--r--widgets/misc/e-timeout-activity.h2
-rw-r--r--widgets/table/Makefile.am6
-rw-r--r--widgets/text/Makefile.am2
43 files changed, 5742 insertions, 2961 deletions
diff --git a/a11y/e-table/Makefile.am b/a11y/e-table/Makefile.am
index 1884c3a1c5..f344d7b8c3 100644
--- a/a11y/e-table/Makefile.am
+++ b/a11y/e-table/Makefile.am
@@ -1,6 +1,7 @@
INCLUDES = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/widgets \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
+ $(E_UTIL_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
-DG_LOG_DOMAIN=\"e-table\"
diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c
index 7be36d043b..e3b1bac053 100644
--- a/calendar/gui/dialogs/comp-editor.c
+++ b/calendar/gui/dialogs/comp-editor.c
@@ -63,9 +63,8 @@
#include "../e-cal-popup.h"
#include "../calendar-config-keys.h"
#include "cal-attachment-select-file.h"
+#include "widgets/misc/e-attachment-paned.h"
-#include "e-attachment-bar.h"
-#include "misc/e-expander.h"
#include "e-util/e-error.h"
#define COMP_EDITOR_GET_PRIVATE(obj) \
@@ -95,12 +94,7 @@ struct _CompEditorPrivate {
GtkNotebook *notebook;
/* Attachment handling */
- GtkWidget *attachment_bar;
- GtkWidget *attachment_scrolled_window;
- GtkWidget *attachment_expander;
- GtkWidget *attachment_expander_label;
- GtkWidget *attachment_expander_icon;
- GtkWidget *attachment_expander_num;
+ GtkWidget *attachment_paned;
/* Manages menus and toolbars */
GtkUIManager *manager;
@@ -169,7 +163,6 @@ static const gchar *ui =
"</ui>";
static void comp_editor_show_help (CompEditor *editor);
-static void setup_widgets (CompEditor *editor);
static void real_edit_comp (CompEditor *editor, ECalComponent *comp);
static gboolean real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean strip_alarms);
@@ -232,391 +225,82 @@ comp_editor_weak_notify_cb (gpointer unused,
}
static void
-attach_message(CompEditor *editor, CamelMimeMessage *msg)
+drag_data_received (CompEditor *editor,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time)
{
- CamelMimePart *mime_part;
- const char *subject;
- guint i;
- char *filename = NULL;
+ EAttachmentPaned *paned;
+ EAttachmentView *view;
- mime_part = camel_mime_part_new();
- camel_mime_part_set_disposition(mime_part, "inline");
- subject = camel_mime_message_get_subject(msg);
- if (subject) {
- char *desc = g_strdup_printf(_("Attached message - %s"), subject);
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
- camel_mime_part_set_description(mime_part, desc);
- g_free(desc);
- } else
- camel_mime_part_set_description(mime_part, _("Attached message"));
-
- i = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
- i++;
- filename = g_strdup_printf ("email%d",i);
- camel_mime_part_set_filename (mime_part, filename);
-
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
- camel_mime_part_set_content_type(mime_part, "message/rfc822");
- e_attachment_bar_attach_mime_part(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
- camel_object_unref(mime_part);
- g_free (filename);
-}
-
-struct _drop_data {
- CompEditor *editor;
-
- GdkDragContext *context;
- /* Only selection->data and selection->length are valid */
- GtkSelectionData *selection;
-
- guint32 action;
- guint info;
- guint time;
-
- unsigned int move:1;
- unsigned int moved:1;
- unsigned int aborted:1;
-};
-
-static void
-drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
-{
-#if 0 /* KILL-BONOBO */
- char *tmp, *str, **urls;
- CamelMimePart *mime_part;
- CamelStream *stream;
- CamelURL *url;
- CamelMimeMessage *msg;
- char *content_type;
- int i, success=FALSE, delete=FALSE;
-
- switch (info) {
- case DND_TYPE_MESSAGE_RFC822:
- d(printf ("dropping a message/rfc822\n"));
- /* write the message(s) out to a CamelStream so we can use it */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, (char *)selection->data, selection->length);
- camel_stream_reset (stream);
-
- msg = camel_mime_message_new ();
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
- attach_message(editor, msg);
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- }
-
- camel_object_unref(msg);
- camel_object_unref(stream);
- break;
- case DND_TYPE_TEXT_URI_LIST:
- case DND_TYPE_NETSCAPE_URL:
- d(printf ("dropping a text/uri-list\n"));
- tmp = g_strndup ((char *)selection->data, selection->length);
- urls = g_strsplit (tmp, "\n", 0);
- g_free (tmp);
-
- for (i = 0; urls[i] != NULL; i++) {
- str = g_strstrip (urls[i]);
- if (urls[i][0] == '#')
- continue;
-
- if (!g_ascii_strncasecmp (str, "mailto:", 7)) {
- /* TODO does not handle mailto now */
- } else {
- url = camel_url_new (str, NULL);
-
- if (url == NULL)
- continue;
-
- if (!g_ascii_strcasecmp (url->protocol, "file"))
- e_attachment_bar_attach
- (E_ATTACHMENT_BAR (editor->priv->attachment_bar),
- url->path,
- "attachment");
- else
- e_attachment_bar_attach_remote_file
- (E_ATTACHMENT_BAR (editor->priv->attachment_bar),
- str, "attachment");
-
- camel_url_free (url);
- }
- }
-
- g_strfreev (urls);
- success = TRUE;
- break;
- case DND_TYPE_TEXT_VCARD:
- case DND_TYPE_TEXT_CALENDAR:
- content_type = gdk_atom_name (selection->type);
- d(printf ("dropping a %s\n", content_type));
-
- mime_part = camel_mime_part_new ();
- camel_mime_part_set_content (mime_part, (char *)selection->data, selection->length, content_type);
- camel_mime_part_set_disposition (mime_part, "inline");
-
- e_attachment_bar_attach_mime_part
- (E_ATTACHMENT_BAR (editor->priv->attachment_bar),
- mime_part);
-
- camel_object_unref (mime_part);
- g_free (content_type);
-
- success = TRUE;
- break;
- case DND_TYPE_X_UID_LIST: {
- GPtrArray *uids;
- char *inptr, *inend;
- CamelFolder *folder;
- CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
- /* NB: This all runs synchronously, could be very slow/hang/block the ui */
-
- uids = g_ptr_array_new();
-
- inptr = (char *)selection->data;
- inend = (char *)(selection->data + selection->length);
- while (inptr < inend) {
- char *start = inptr;
-
- while (inptr < inend && *inptr)
- inptr++;
-
- if (start > (char *)selection->data)
- g_ptr_array_add(uids, g_strndup(start, inptr-start));
-
- inptr++;
- }
-
- if (uids->len > 0) {
- folder = mail_tool_uri_to_folder((char *)selection->data, 0, &ex);
- if (folder) {
- if (uids->len == 1) {
- msg = camel_folder_get_message(folder, uids->pdata[0], &ex);
- if (msg == NULL)
- goto fail;
- attach_message(editor, msg);
- } else {
- CamelMultipart *mp = camel_multipart_new();
- char *desc;
- char *filename = NULL;
- guint num;
-
- camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/digest");
- camel_multipart_set_boundary(mp, NULL);
- for (i=0;i<uids->len;i++) {
-
- msg = camel_folder_get_message(folder, uids->pdata[i], &ex);
- if (msg) {
- mime_part = camel_mime_part_new();
- camel_mime_part_set_disposition(mime_part, "inline");
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
- camel_mime_part_set_content_type(mime_part, "message/rfc822");
- camel_multipart_add_part(mp, mime_part);
- camel_object_unref(mime_part);
- camel_object_unref(msg);
- } else {
- camel_object_unref(mp);
- goto fail;
- }
- }
- mime_part = camel_mime_part_new();
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)mp);
- /* translators, this count will always be >1 */
- desc = g_strdup_printf(ngettext("Attached message", "%d attached messages", uids->len), uids->len);
- camel_mime_part_set_description(mime_part, desc);
- g_free(desc);
-
- num = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
- num++;
- filename = g_strdup_printf ("email%d", num);
- camel_mime_part_set_filename (mime_part, filename);
-
- e_attachment_bar_attach_mime_part
- (E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
- camel_object_unref(mime_part);
- camel_object_unref(mp);
- g_free (filename);
- }
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- fail:
- if (camel_exception_is_set(&ex)) {
- char *name;
-
- camel_object_get(folder, NULL, CAMEL_FOLDER_NAME, &name, NULL);
- e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
- name?name:(char *)selection->data, camel_exception_get_description(&ex), NULL);
- camel_object_free(folder, CAMEL_FOLDER_NAME, name);
- }
- camel_object_unref(folder);
- } else {
- e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
- (char *)selection->data, camel_exception_get_description(&ex), NULL);
- }
-
- camel_exception_clear(&ex);
- }
-
- g_ptr_array_free(uids, TRUE);
-
- break; }
- default:
- d(printf ("dropping an unknown\n"));
- break;
- }
-
- printf("Drag finished, success %d delete %d\n", success, delete);
-
- gtk_drag_finish(context, success, delete, time);
-#endif
-}
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->editor, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->editor, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- gtk_drag_finish(m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
- struct _drop_data *m = data;
-
- g_slist_free(items);
-
- g_object_unref(m->context);
- g_object_unref(m->editor);
- g_free(m->selection->data);
- g_free(m->selection);
- g_free(m);
-}
-
-static void
-drag_data_received (CompEditor *editor, GdkDragContext *context,
- int x, int y, GtkSelectionData *selection,
- guint info, guint time)
-{
- if (selection->data == NULL || selection->length == -1)
- return;
-
- if (context->action == GDK_ACTION_ASK) {
- ECalPopup *ecp;
- GSList *menus = NULL;
- GtkMenu *menu;
- int i;
- struct _drop_data *m;
-
- m = g_malloc0(sizeof(*m));
- m->context = context;
- g_object_ref(context);
- m->editor = editor;
- g_object_ref(editor);
- m->action = context->action;
- m->info = info;
- m->time = time;
- m->selection = g_malloc0(sizeof(*m->selection));
- m->selection->data = g_malloc(selection->length);
- memcpy(m->selection->data, selection->data, selection->length);
- m->selection->length = selection->length;
-
- ecp = e_cal_popup_new("org.gnome.evolution.calendar.editor.popup.drop");
- for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
- menus = g_slist_append(menus, &drop_popup_menu[i]);
-
- e_popup_add_items((EPopup *)ecp, menus, NULL, drop_popup_free, m);
- menu = e_popup_create_menu_once((EPopup *)ecp, NULL, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
- } else {
- drop_action(editor, context, context->action, selection, info, time);
- }
+ e_attachment_view_drag_data_received (
+ view, context, x, y, selection, info, time);
}
static gboolean
-drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, CompEditor *editor)
-{
- GList *targets;
- GdkDragAction action, actions = 0;
-
- for (targets = context->targets; targets; targets = targets->next) {
- int i;
-
- for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
- if (targets->data == (void *)drag_info[i].atom)
- actions |= drag_info[i].actions;
- }
-
- actions &= context->actions;
- action = context->suggested_action;
- /* we default to copy */
- if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
- action = GDK_ACTION_COPY;
-
- gdk_drag_status(context, action, time);
-
- return action != 0;
-}
-
-static void
-add_to_bar (CompEditor *editor, GPtrArray *file_list, int is_inline)
+drag_motion (CompEditor *editor,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
{
- CompEditorPrivate *priv = editor->priv;
- int i;
-
- for (i = 0; i < file_list->len; i++) {
- CamelURL *url;
+ EAttachmentPaned *paned;
+ EAttachmentView *view;
- if (!(url = camel_url_new (file_list->pdata[i], NULL)))
- continue;
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
- if (!g_ascii_strcasecmp (url->protocol, "file")) {
- e_attachment_bar_attach((EAttachmentBar *)priv->attachment_bar, url->path, is_inline ? "inline" : "attachment");
- } else {
- e_attachment_bar_attach_remote_file ((EAttachmentBar *)priv->attachment_bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
- }
-
- camel_url_free (url);
- }
+ return e_attachment_view_drag_motion (view, context, x, y, time);
}
static GSList *
get_attachment_list (CompEditor *editor)
{
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
GSList *parts = NULL, *list = NULL, *p = NULL;
const char *comp_uid = NULL;
const char *local_store = e_cal_get_local_attachment_store (editor->priv->client);
+ gboolean valid;
int ticker=0;
+
e_cal_component_get_uid (editor->priv->comp, &comp_uid);
- parts = e_attachment_bar_get_parts((EAttachmentBar *)editor->priv->attachment_bar);
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
- for (p = parts; p!=NULL ; p = p->next) {
+ model = GTK_TREE_MODEL (store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ EAttachment *attachment;
CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
CamelStream *stream;
char *attach_file_url;
char *safe_fname, *utf8_safe_fname;
char *filename;
+ gint column_id;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_object_unref (attachment);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+
+ if (mime_part == NULL)
+ continue;
wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (p->data));
@@ -997,20 +681,15 @@ static void
action_attach_cb (GtkAction *action,
CompEditor *editor)
{
- GPtrArray *file_list;
- gboolean is_inline = FALSE;
- int i;
-
- file_list = comp_editor_select_file_attachments (editor, &is_inline);
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
- if (file_list) {
- add_to_bar (editor, file_list, is_inline);
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
- for (i = 0; i < file_list->len; i++)
- g_free (file_list->pdata[i]);
-
- g_ptr_array_free (file_list, TRUE);
- }
+ e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor));
}
static void
@@ -1136,12 +815,19 @@ action_save_cb (GtkAction *action,
CompEditor *editor)
{
CompEditorPrivate *priv = editor->priv;
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
ECalComponentText text;
gboolean delegated = FALSE;
gboolean read_only, correct = FALSE;
ECalComponent *comp;
- if (e_attachment_bar_get_download_count (E_ATTACHMENT_BAR (editor->priv->attachment_bar)) ){
+ paned = E_ATTACHMENT_PANED (priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
+
+ if (e_attachment_store_get_num_downloading (store) > 0) {
gboolean response = 1;
/*FIXME: Cannot use mail functions from calendar!!!! */
#if 0
@@ -1693,6 +1379,44 @@ comp_editor_map (GtkWidget *widget)
GTK_WIDGET_CLASS (comp_editor_parent_class)->map (widget);
}
+static gboolean
+comp_editor_delete_event (GtkWidget *widget,
+ GdkEventAny *event)
+{
+ CompEditor *editor;
+
+ editor = COMP_EDITOR (widget);
+
+ commit_all_fields (editor);
+
+ if (prompt_and_save_changes (editor, TRUE))
+ close_dialog (editor);
+
+ return TRUE;
+}
+
+static gboolean
+comp_editor_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ CompEditor *editor;
+
+ editor = COMP_EDITOR (editor);
+
+ if (event->keyval == GDK_Escape) {
+ commit_all_fields (editor);
+
+ if (prompt_and_save_changes (editor, TRUE))
+ close_dialog (editor);
+
+ return TRUE;
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (comp_editor_parent_class)->
+ key_press_event (widget, event);
+}
+
static void
comp_editor_class_init (CompEditorClass *class)
{
@@ -1713,6 +1437,8 @@ comp_editor_class_init (CompEditorClass *class)
widget_class = GTK_WIDGET_CLASS (class);
widget_class->map = comp_editor_map;
+ widget_class->delete_event = comp_editor_delete_event;
+ widget_class->key_press_event = comp_editor_key_press_event;
class->help_section = "usage-calendar";
class->edit_comp = real_edit_comp;
@@ -1778,8 +1504,12 @@ static void
comp_editor_init (CompEditor *editor)
{
CompEditorPrivate *priv;
+ EAttachmentPaned *paned;
+ EAttachmentView *view;
GtkActionGroup *action_group;
GtkAction *action;
+ GtkWidget *container;
+ GtkWidget *widget;
EShell *shell;
GError *error = NULL;
@@ -1795,17 +1525,18 @@ comp_editor_init (CompEditor *editor)
priv->changed = FALSE;
priv->needs_send = FALSE;
priv->mod = CALOBJ_MOD_ALL;
- priv->existing_org = FALSE;
- priv->user_org = FALSE;
- priv->warned = FALSE;
+ priv->existing_org = FALSE;
+ priv->user_org = FALSE;
+ priv->warned = FALSE;
priv->is_group_item = FALSE;
- priv->attachment_bar = e_attachment_bar_new ();
priv->manager = gtk_ui_manager_new ();
- gtk_window_add_accel_group (
- GTK_WINDOW (editor),
- gtk_ui_manager_get_accel_group (priv->manager));
+ gtk_window_add_accel_group (
+ GTK_WINDOW (editor),
+ gtk_ui_manager_get_accel_group (priv->manager));
+
+ /* Setup Action Groups */
action_group = gtk_action_group_new ("core");
gtk_action_group_set_translation_domain (
@@ -1831,10 +1562,6 @@ comp_editor_init (CompEditor *editor)
G_N_ELEMENTS (classification_radio_entries),
E_CAL_COMPONENT_CLASS_PUBLIC,
NULL, NULL); /* no callback */
- action = e_attachment_bar_recent_action_new (
- E_ATTACHMENT_BAR (priv->attachment_bar),
- "attach-recent", _("Recent _Documents"));
- gtk_action_group_add_action (action_group, action);
gtk_ui_manager_insert_action_group (
priv->manager, action_group, 0);
g_object_unref (action_group);
@@ -1864,12 +1591,52 @@ comp_editor_init (CompEditor *editor)
g_error_free (error);
}
- setup_widgets (editor);
+ /* Setup Widgets */
+
+ container = GTK_WIDGET (editor);
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = comp_editor_get_managed_widget (editor, "/main-menu");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = e_attachment_paned_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->attachment_paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = e_attachment_paned_get_content_area (
+ E_ATTACHMENT_PANED (priv->attachment_paned));
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->notebook = GTK_NOTEBOOK (widget);
+ gtk_widget_show (widget);
+
+ /* Add a GtkRecentAction to the "individual" action group. */
+ action_group = comp_editor_get_action_group (editor, "individual");
+ paned = E_ATTACHMENT_PANED (priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ action = e_attachment_view_recent_action_new (
+ view, "attach-recent", _("Recent _Documents"));
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (action);
/* DND support */
gtk_drag_dest_set (GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
g_signal_connect(editor, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
- g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), editor);
+ g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), NULL);
gtk_window_set_type_hint (GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
@@ -1928,170 +1695,17 @@ prompt_and_save_changes (CompEditor *editor, gboolean send)
}
}
-static int
-delete_event_cb (GtkWidget *widget,
- GdkEvent *event,
- CompEditor *editor)
-{
- commit_all_fields (editor);
-
- if (prompt_and_save_changes (editor, TRUE))
- close_dialog (editor);
-
- return TRUE;
-}
-
static void
-attachment_bar_changed_cb (EAttachmentBar *bar,
- CompEditor *editor)
+attachment_store_changed_cb (CompEditor *editor)
{
- guint attachment_num = e_attachment_bar_get_num_attachments (
- E_ATTACHMENT_BAR (editor->priv->attachment_bar));
- if (attachment_num) {
- gchar *num_text = g_strdup_printf (
- ngettext ("<b>%d</b> Attachment", "<b>%d</b> Attachments", attachment_num),
- attachment_num);
- gtk_label_set_markup (GTK_LABEL (editor->priv->attachment_expander_num),
- num_text);
- g_free (num_text);
-
- gtk_widget_show (editor->priv->attachment_expander_icon);
- e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),TRUE);
-
- } else {
- gtk_label_set_text (GTK_LABEL (editor->priv->attachment_expander_num), "");
- gtk_widget_hide (editor->priv->attachment_expander_icon);
- e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),FALSE);
- }
-
-
/* Mark the editor as changed so it prompts about unsaved
changes on close */
comp_editor_set_changed (editor, TRUE);
-
-}
-
-static void
-attachment_expander_activate_cb (EExpander *expander,
- void *data)
-{
- CompEditor *editor = COMP_EDITOR (data);
- gboolean show = e_expander_get_expanded (expander);
-
- /* Update the expander label */
- if (show)
- gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
- _("Hide Attachment _Bar"));
- else
- gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
- _("Show Attachment _Bar"));
-}
-
-
-/* GtkWidget methods. */
-
-static gint
-editor_key_press_event (CompEditor *editor,
- GdkEventKey *event)
-{
- if (event->keyval == GDK_Escape) {
- commit_all_fields (editor);
-
- if (prompt_and_save_changes (editor, TRUE))
- close_dialog (editor);
-
- return TRUE;
- }
-
- return FALSE;
}
/* Menu callbacks */
static void
-setup_widgets (CompEditor *editor)
-{
- CompEditorPrivate *priv;
- GtkWidget *expander_hbox;
- GtkWidget *widget;
- GtkWidget *vbox;
-
- priv = editor->priv;
-
- /* Useful vbox */
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (editor), vbox);
- gtk_widget_show (vbox);
-
- /* Main Menu */
- widget = comp_editor_get_managed_widget (editor, "/main-menu");
- gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
- gtk_widget_show (widget);
-
- /* Main Toolbar */
- widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
- gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
- gtk_widget_show (widget);
-
- /* Notebook */
- widget = gtk_notebook_new ();
- gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
- gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
- gtk_widget_show (widget);
- priv->notebook = GTK_NOTEBOOK (widget);
-
- g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), editor);
- g_signal_connect (editor, "key_press_event", G_CALLBACK (editor_key_press_event), editor);
-
- /*Attachments */
- priv->attachment_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
- GTK_SHADOW_IN);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- GTK_WIDGET_SET_FLAGS (priv->attachment_bar, GTK_CAN_FOCUS);
- gtk_container_add (GTK_CONTAINER (priv->attachment_scrolled_window),
- priv->attachment_bar);
- gtk_widget_show (priv->attachment_bar);
- g_signal_connect (priv->attachment_bar, "changed",
- G_CALLBACK (attachment_bar_changed_cb), editor);
- priv->attachment_expander_label =
- gtk_label_new_with_mnemonic (_("Show Attachment _Bar"));
- priv->attachment_expander_num = gtk_label_new ("");
- gtk_label_set_use_markup (GTK_LABEL (priv->attachment_expander_num), TRUE);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_label), 0.0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_num), 1.0, 0.5);
- expander_hbox = gtk_hbox_new (FALSE, 0);
-
- priv->attachment_expander_icon = gtk_image_new_from_icon_name ("mail-attachment", GTK_ICON_SIZE_MENU);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_icon), 1, 0.5);
- gtk_widget_set_size_request (priv->attachment_expander_icon, 100, -1);
-
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_label,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_icon,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_num,
- TRUE, TRUE, 0);
- gtk_widget_show_all (expander_hbox);
- gtk_widget_hide (priv->attachment_expander_icon);
-
- priv->attachment_expander = e_expander_new ("");
- e_expander_set_label_widget (E_EXPANDER (priv->attachment_expander), expander_hbox);
- atk_object_set_name (gtk_widget_get_accessible (priv->attachment_expander), _("Show Attachments"));
- atk_object_set_description (gtk_widget_get_accessible (priv->attachment_expander), _("Press space key to toggle attachment bar"));
- gtk_container_add (GTK_CONTAINER (priv->attachment_expander), priv->attachment_scrolled_window);
-
- gtk_box_pack_start (GTK_BOX (vbox), priv->attachment_expander, FALSE, FALSE, 4);
- gtk_widget_show (priv->attachment_expander);
- e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), FALSE);
- g_signal_connect_after (priv->attachment_expander, "activate",
- G_CALLBACK (attachment_expander_activate_cb), editor);
-}
-
-
-static void
comp_editor_show_help (CompEditor *editor)
{
CompEditorClass *class;
@@ -2637,12 +2251,16 @@ comp_editor_get_client (CompEditor *editor)
static void
set_attachment_list (CompEditor *editor, GSList *attach_list)
{
- GSList *p = NULL;
- const char *comp_uid= NULL;
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ GSList *iter = NULL;
- e_cal_component_get_uid (editor->priv->comp, &comp_uid);
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
- if (e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar))) {
+ if (e_attachment_store_get_num_attachments (store) > 0) {
/* To prevent repopulating the
* bar due to redraw functions in fill_widget.
* Assumes it can be set only once.
@@ -2650,100 +2268,42 @@ set_attachment_list (CompEditor *editor, GSList *attach_list)
return;
}
- for (p = attach_list; p != NULL; p = p->next) {
- char *attach_filename;
- CamelMimePart *part;
- CamelDataWrapper *wrapper;
- CamelStream *stream;
- struct stat statbuf;
- char *mime_type, *file_name;
- char *ptr;
-
- attach_filename = (char *) p->data;
- /* should we assert if g_str_has_prefix (attach_filename, "file://"))
- * here
- */
- /* get url sans protocol and add it to the bar.
- * how to set the filename properly */
- file_name = g_filename_from_uri (attach_filename, NULL, NULL);
- if (!file_name)
- continue;
-
- if (g_stat (file_name, &statbuf) < 0) {
- g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
- g_free (file_name);
- continue;
- }
-
- /* return if it's not a regular file */
- if (!S_ISREG (statbuf.st_mode)) {
- g_warning ("Cannot attach file %s: not a regular file", file_name);
- g_free (file_name);
- return;
- }
+ for (iter = attach_list; iter != NULL; iter = iter->next) {
+ EAttachment *attachment;
+ const gchar *uri = iter->data;
- stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0);
- if (!stream) {
- g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
- g_free (file_name);
- return;
- }
-
- mime_type = e_util_guess_mime_type (file_name, TRUE);
- if (mime_type) {
- if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
- wrapper = (CamelDataWrapper *) camel_mime_message_new ();
- } else {
- wrapper = camel_data_wrapper_new ();
- }
-
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
- g_free (mime_type);
- } else {
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
- }
-
- camel_object_unref (stream);
-
- part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
- camel_object_unref (wrapper);
-
- camel_mime_part_set_disposition (part, "attachment");
-
- ptr = strstr (file_name, comp_uid);
- if (ptr) {
- ptr += strlen(comp_uid);
- if (*ptr++ == '-')
- camel_mime_part_set_filename (part, ptr);
- }
- g_free (file_name);
-
- e_attachment_bar_attach_mime_part ((EAttachmentBar *) editor->priv->attachment_bar, part);
- e_expander_set_expanded (E_EXPANDER (editor->priv->attachment_expander), TRUE);
-
- camel_object_unref (part);
+ attachment = e_attachment_new_for_uri (uri);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
}
}
static void
fill_widgets (CompEditor *editor)
{
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
CompEditorPrivate *priv;
GList *l;
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
+
priv = editor->priv;
/*Check if attachments are available here and set them*/
if (e_cal_component_has_attachments (priv->comp)) {
GSList *attachment_list = NULL;
e_cal_component_get_attachment_list (priv->comp, &attachment_list);
- g_signal_handlers_block_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+ g_signal_handlers_block_by_func (
+ store, G_CALLBACK (attachment_store_changed_cb),
+ editor);
set_attachment_list (editor, attachment_list);
- g_signal_handlers_unblock_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+ g_signal_handlers_unblock_by_func(
+ store, G_CALLBACK (attachment_store_changed_cb),
+ editor);
g_slist_foreach (attachment_list, (GFunc)g_free, NULL);
g_slist_free (attachment_list);
}
@@ -3068,20 +2628,43 @@ comp_editor_close (CompEditor *editor)
GSList *
comp_editor_get_mime_attach_list (CompEditor *editor)
{
+ EAttachmentPaned *paned;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
struct CalMimeAttach *cal_mime_attach;
- GSList *attach_list = NULL, *l, *parts;
+ GSList *attach_list = NULL;
+ gboolean valid;
+
+ paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned);
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
- /* TODO assert sanity of bar */
- parts = e_attachment_bar_get_parts (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
- for (l = parts; l ; l = l->next) {
+ model = GTK_TREE_MODEL (store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+ while (valid) {
+ EAttachment *attachment;
CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
CamelStreamMem *mstream;
unsigned char *buffer = NULL;
const char *desc, *disp;
+ gint column_id;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_object_unref (attachment);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+
+ if (mime_part == NULL)
+ continue;
cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach));
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (l->data));
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
mstream = (CamelStreamMem *) camel_stream_mem_new ();
camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
@@ -3089,15 +2672,14 @@ comp_editor_get_mime_attach_list (CompEditor *editor)
cal_mime_attach->encoded_data = (char *)buffer;
cal_mime_attach->length = mstream->buffer->len;
- cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename
- ((CamelMimePart *) l->data));
- desc = camel_mime_part_get_description ((CamelMimePart *) l->data);
+ cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename (mime_part));
+ desc = camel_mime_part_get_description (mime_part);
if (!desc || *desc == '\0')
desc = _("attachment");
cal_mime_attach->description = g_strdup (desc);
cal_mime_attach->content_type = g_strdup (camel_data_wrapper_get_mime_type (wrapper));
- disp = camel_mime_part_get_disposition ((CamelMimePart *)l->data);
+ disp = camel_mime_part_get_disposition (mime_part);
if (disp && !g_ascii_strcasecmp(disp, "inline"))
cal_mime_attach->disposition = TRUE;
@@ -3107,8 +2689,6 @@ comp_editor_get_mime_attach_list (CompEditor *editor)
}
- g_slist_free (parts);
-
return attach_list;
}
diff --git a/calendar/gui/e-cal-popup.c b/calendar/gui/e-cal-popup.c
index 1495e10506..5839991060 100644
--- a/calendar/gui/e-cal-popup.c
+++ b/calendar/gui/e-cal-popup.c
@@ -86,395 +86,11 @@ ecalp_target_free(EPopup *ep, EPopupTarget *t)
/* Standard menu code */
-static char *
-temp_save_part(CamelMimePart *part, char *path, gboolean file)
-{
- const char *filename;
- char *tmpdir, *utf8_mfilename = NULL, *mfilename = NULL, *usepath;
- CamelStream *stream;
- CamelDataWrapper *wrapper;
-
- if (!path) {
- tmpdir = e_mkdtemp("evolution-tmp-XXXXXX");
- if (tmpdir == NULL) {
- return NULL;
- }
-
- filename = camel_mime_part_get_filename (part);
- if (filename == NULL) {
- /* This is the default filename used for temporary file creation */
- filename = _("Unknown");
- } else {
- utf8_mfilename = g_strdup (filename);
- e_filename_make_safe (utf8_mfilename);
- mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
- g_free (utf8_mfilename);
- filename = (const char *) mfilename;
- }
-
- path = g_build_filename(tmpdir, filename, NULL);
- g_free(tmpdir);
- g_free(mfilename);
- } else if (!file) {
- tmpdir = path;
- filename = camel_mime_part_get_filename (part);
- if (filename == NULL) {
- /* This is the default filename used for temporary file creation */
- filename = _("Unknown");
- } else {
- utf8_mfilename = g_strdup (filename);
- e_filename_make_safe (utf8_mfilename);
- mfilename = g_filename_from_utf8 ((const char *)utf8_mfilename, -1, NULL, NULL, NULL);
- g_free (utf8_mfilename);
- filename = (const char *) mfilename;
- }
-
- path = g_build_filename(tmpdir, filename, NULL);
- g_free(mfilename);
- }
-
- if (strstr (path, "://"))
- usepath = path;
- else
- usepath = g_strjoin (NULL, "file://", path, NULL);
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
- stream = camel_stream_vfs_new_with_uri (usepath, CAMEL_STREAM_VFS_CREATE);
-
- if (usepath != path)
- g_free (usepath);
-
- if (!stream) {
- /* TODO handle error conditions */
- g_message ("DEBUG: could not open the file to write\n");
- return NULL;
- }
-
- if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) {
- camel_stream_close (stream);
- camel_object_unref (stream);
- g_message ("DEBUG: could not write to file\n");
- return NULL;
- }
-
- camel_stream_close(stream);
- camel_object_unref(stream);
-
- return path;
-}
-
-static void
-ecalp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
-{
- EPopupTarget *t = ep->target;
- EAttachment *attachment;
- CamelMimePart *part = NULL;
- char *file, *mfilename = NULL;
- const char *filename;
-
- attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) t)->attachments->data);
- part = e_attachment_get_mime_part (attachment);
- filename = camel_mime_part_get_filename (part);
- if (filename == NULL) {
- /* This is the default filename used for temporary file creation */
- filename = _("Unknown");
- } else {
- mfilename = g_strdup(filename);
- e_filename_make_safe(mfilename);
- filename = mfilename;
- }
- file = e_file_dialog_save (_("Save As..."), filename);
-
- if (file)
- temp_save_part (part, file, TRUE);
-
- g_free (file);
- g_free (mfilename);
-}
-
-static void
-ecalp_part_popup_save_selected(EPopup *ep, EPopupItem *item, void *data)
-{
- GSList *parts;
- EPopupTarget *t = ep->target;
- char *dir, *path;
-
- dir = e_file_dialog_save_folder (_("Select folder to save selected attachments..."));
- parts = ((ECalPopupTargetAttachments *) t)->attachments;
-
- for (;parts; parts=parts->next) {
- EAttachment *attachment = parts->data;
- CamelMimePart *mime_part;
-
- mime_part = e_attachment_get_mime_part (attachment);
- path = temp_save_part (mime_part, dir, FALSE);
- /* Probably we 'll do some reporting in next release, like listing the saved files and locations */
- g_free (path);
- }
-}
-
-static void
-ecalp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
-{
- EAttachment *attachment;
- EPopupTarget *t = ep->target;
- GConfClient *gconf;
- char *str, *filename, *path, *extension;
- unsigned int i=1;
- CamelMimePart *part;
-
- attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) t)->attachments->data);
- part = e_attachment_get_mime_part (attachment);
-
- if (!part)
- return;
-
- filename = g_strdup(camel_mime_part_get_filename(part));
-
- /* if filename is blank, create a default filename based on MIME type */
- if (!filename || !filename[0]) {
- CamelContentType *ct;
-
- ct = camel_mime_part_get_content_type(part);
- g_free (filename);
- filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype);
- }
-
- e_filename_make_safe(filename);
-
- path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL);
-
- extension = strrchr(filename, '.');
- if (extension)
- *extension++ = 0;
-
- /* if file exists, stick a (number) on the end */
- while (g_file_test(path, G_FILE_TEST_EXISTS)) {
- char *name;
- name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension);
- g_free(path);
- path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL);
- g_free(name);
- }
-
- g_free(filename);
-
- if (temp_save_part(part, path, TRUE)) {
- gconf = gconf_client_get_default();
-
- /* if the filename hasn't changed, blank the filename before
- * setting it so that gconf detects a change and updates it */
- if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL
- && strcmp (str, path) == 0) {
- gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL);
- }
-
- g_free (str);
- gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL);
-
- /* if GNOME currently doesn't display a picture, set to "wallpaper"
- * display mode, otherwise leave it alone */
- if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL
- || strcmp(str, "none") == 0) {
- gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL);
- }
-
- gconf_client_suggest_sync(gconf, NULL);
-
- g_free(str);
- g_object_unref(gconf);
- }
-
- g_free(path);
-}
-
-static const EPopupItem ecalp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
-
-static ECalPopupItem ecalp_attachment_object_popups[] = {
- { E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), ecalp_part_popup_saveas, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_ONE },
- { E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), ecalp_part_popup_set_background, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_IMAGE },
- { E_POPUP_ITEM, "00.attach.20", N_("_Save Selected"), ecalp_part_popup_save_selected, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_MULTIPLE },
- { E_POPUP_BAR, "05.attach", },
-};
-
-static void
-ecalp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
-{
- char *path;
- EAttachment *attachment;
- EPopupTarget *target = ep->target;
- CamelMimePart *part;
-
- attachment = E_ATTACHMENT (((ECalPopupTargetAttachments *) target)->attachments->data);
- part = e_attachment_get_mime_part (attachment);
-
- path = temp_save_part(part, NULL, FALSE);
- if (path) {
- GAppInfo *app = item->user_data;
- GList *uris = NULL;
- GError *error = NULL;
-
- if (g_app_info_supports_files (app)) {
- GFile *file = g_file_new_for_path (path);
-
- uris = g_list_append (uris, file);
- g_app_info_launch (app, uris, NULL, &error);
- g_object_unref (file);
- } else {
- char *uri;
-
- uri = e_util_filename_to_uri (path);
- uris = g_list_append (uris, uri);
-
- g_app_info_launch_uris (app, uris, NULL, &error);
- g_free (uri);
- }
-
- if (error) {
- g_warning ("%s", error->message);
- g_error_free (error);
- }
-
- g_list_free (uris);
- g_free (path);
- }
-}
-
-static void
-ecalp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
-{
- while (free_list) {
- GSList *n = free_list->next;
- EPopupItem *item = free_list->data;
-
- if (item->user_data && item->activate == ecalp_apps_open_in)
- g_object_unref (item->user_data);
-
- g_free(item->path);
- g_free(item->label);
- g_free(item);
- g_slist_free_1(free_list);
-
- free_list = n;
- }
-}
-
-static void
-ecalp_standard_items_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
-static void
-ecalp_standard_menu_factory (EPopup *ecalp, void *data)
-{
- int i, len;
- EPopupItem *items;
- GSList *menus = NULL;
- GList *apps = NULL;
- char *mime_type = NULL;
- const char *filename = NULL;
-
- switch (ecalp->target->type) {
- case E_CAL_POPUP_TARGET_ATTACHMENTS: {
- ECalPopupTargetAttachments *t = (ECalPopupTargetAttachments *)ecalp->target;
- GSList *list = t->attachments;
- EAttachment *attachment;
- CamelMimePart *mime_part;
-
- items = ecalp_attachment_object_popups;
- len = G_N_ELEMENTS(ecalp_attachment_object_popups);
-
- if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
- break;
- }
-
- /* Only one attachment selected */
- attachment = list->data;
- mime_part = e_attachment_get_mime_part (attachment);
- mime_type = camel_data_wrapper_get_mime_type (CAMEL_DATA_WRAPPER (mime_part));
- filename = camel_mime_part_get_filename (mime_part);
-
-
- break; }
- default:
- items = NULL;
- len = 0;
- }
-
- if (mime_type) {
- gchar *cp;
-
- /* does gvfs expect lowercase MIME types? */
- for (cp = mime_type; *cp != '\0'; cp++)
- *cp = g_ascii_tolower (*cp);
-
- cp = g_content_type_from_mime_type (mime_type);
- apps = g_app_info_get_all_for_type (cp ? cp : mime_type);
- g_free (cp);
-
- if (apps == NULL && strcmp(mime_type, "application/octet-stream") == 0) {
- if (filename) {
- gchar *name_type;
-
- name_type = e_util_guess_mime_type (filename, FALSE);
- cp = g_content_type_from_mime_type (name_type);
- apps = g_app_info_get_all_for_type (cp ? cp : name_type);
- g_free (cp);
- g_free (name_type);
- }
- }
- g_free (mime_type);
-
- if (apps) {
- GSList *open_menus = NULL;
- GList *l;
-
- menus = g_slist_prepend(menus, (void *)&ecalp_standard_part_apps_bar);
-
- for (l = apps, i = 0; l; l = l->next, i++) {
- GAppInfo *app = l->data;
- EPopupItem *item;
-
- if (!g_app_info_should_show (app)) {
- g_object_unref (app);
- l->data = NULL;
- continue;
- }
-
- item = g_malloc0(sizeof(*item));
- item->type = E_POPUP_ITEM;
- item->path = g_strdup_printf("99.object.%02d", i);
- item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app));
- item->activate = ecalp_apps_open_in;
- item->user_data = app;
-
- open_menus = g_slist_prepend(open_menus, item);
- }
-
- if (open_menus)
- e_popup_add_items(ecalp, open_menus, NULL, ecalp_apps_popup_free, NULL);
-
- g_list_free (apps);
- }
- }
-
- for (i=0;i<len;i++) {
- if ((items[i].visible & ecalp->target->mask) == 0)
- menus = g_slist_prepend(menus, &items[i]);
- }
-
- if (menus)
- e_popup_add_items(ecalp, menus, NULL, ecalp_standard_items_free, NULL);
-}
-
static void
ecalp_class_init(GObjectClass *klass)
{
klass->finalize = ecalp_finalise;
((EPopupClass *)klass)->target_free = ecalp_target_free;
-
- e_popup_class_add_factory((EPopupClass *)klass, NULL, ecalp_standard_menu_factory, NULL);
}
GType
@@ -763,64 +379,6 @@ e_cal_popup_target_new_source(ECalPopup *eabp, ESourceSelector *selector)
return t;
}
-/**
- * e_cal_popup_target_new_attachments:
- * @ecp:
- * @attachments: A list of CalAttachment objects, reffed for
- * the list. Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-ECalPopupTargetAttachments *
-e_cal_popup_target_new_attachments(ECalPopup *ecp, CompEditor *editor, GSList *attachments)
-{
- ECalPopupTargetAttachments *t = e_popup_target_new(&ecp->popup, E_CAL_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
- guint32 mask = ~0;
- int len = g_slist_length(attachments);
- ECal *client = comp_editor_get_client (editor);
- CompEditorFlags flags = comp_editor_get_flags (editor);
- gboolean read_only = FALSE;
- GError *error = NULL;
-
- if (!e_cal_is_read_only (client, &read_only, &error)) {
- if (error->code != E_CALENDAR_STATUS_BUSY)
- read_only = TRUE;
- g_error_free (error);
- }
-
- if (!read_only && (!(flags & COMP_EDITOR_MEETING) ||
- (flags & COMP_EDITOR_NEW_ITEM) ||
- (flags & COMP_EDITOR_USER_ORG)))
- mask &= ~ E_CAL_POPUP_ATTACHMENTS_MODIFY;
-
- t->attachments = attachments;
- if (len > 0)
- mask &= ~ E_CAL_POPUP_ATTACHMENTS_MANY;
-
- if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
- EAttachment *attachment;
- CamelMimePart *mime_part;
- CamelContentType *mime_type;
-
- attachment = attachments->data;
- mime_part = e_attachment_get_mime_part (attachment);
- mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type;
-
- if (camel_content_type_is (mime_type, "image", "*"))
- mask &= ~ E_CAL_POPUP_ATTACHMENTS_IMAGE;
- mask &= ~ E_CAL_POPUP_ATTACHMENTS_ONE;
- }
-
- if (len > 1)
- mask &= ~ E_CAL_POPUP_ATTACHMENTS_MULTIPLE;
-
- t->target.mask = mask;
-
- return t;
-}
-
/* ********************************************************************** */
/* Popup menu plugin handler */
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c
index 01c05ecc61..2af7a63fcd 100644
--- a/composer/e-composer-actions.c
+++ b/composer/e-composer-actions.c
@@ -29,69 +29,13 @@ static void
action_attach_cb (GtkAction *action,
EMsgComposer *composer)
{
- EAttachmentBar *bar;
- GtkWidget *dialog;
- GtkWidget *option;
- GSList *uris, *iter;
- const gchar *disposition;
- gboolean active;
- gint response;
-
- bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-
- dialog = gtk_file_chooser_dialog_new (
- _("Insert Attachment"),
- GTK_WINDOW (composer),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- _("A_ttach"), GTK_RESPONSE_OK,
- NULL);
-
- gtk_dialog_set_default_response (
- GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- gtk_file_chooser_set_local_only (
- GTK_FILE_CHOOSER (dialog), FALSE);
- gtk_file_chooser_set_select_multiple (
- GTK_FILE_CHOOSER (dialog), TRUE);
- gtk_window_set_icon_name (
- GTK_WINDOW (dialog), "mail-message-new");
+ EAttachmentView *view;
+ EAttachmentStore *store;
- option = gtk_check_button_new_with_mnemonic (
- _("_Suggest automatic display of attachment"));
- gtk_widget_show (option);
- gtk_file_chooser_set_extra_widget (
- GTK_FILE_CHOOSER (dialog), option);
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
- response = gtkhtml_editor_file_chooser_dialog_run (
- GTKHTML_EDITOR (composer), dialog);
-
- if (response != GTK_RESPONSE_OK)
- goto exit;
-
- uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
- active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
- disposition = active ? "inline" : "attachment";
-
- for (iter = uris; iter != NULL; iter = iter->next) {
- CamelURL *url;
-
- url = camel_url_new (iter->data, NULL);
- if (url == NULL)
- continue;
-
- if (!g_ascii_strcasecmp (url->protocol, "file"))
- e_attachment_bar_attach (bar, url->path, disposition);
- else
- e_attachment_bar_attach_remote_file (bar, iter->data, disposition);
-
- camel_url_free (url);
- }
-
- g_slist_foreach (uris, (GFunc) g_free, NULL);
- g_slist_free (uris);
-
-exit:
- gtk_widget_destroy (dialog);
+ e_attachment_store_run_load_dialog (store, GTK_WINDOW (composer));
}
static void
@@ -327,10 +271,10 @@ static void
action_new_message_cb (GtkAction *action,
EMsgComposer *composer)
{
- GtkWidget *widget;
+ EMsgComposer *new_composer;
- widget = e_msg_composer_new ();
- gtk_widget_show (widget);
+ new_composer = e_msg_composer_new ();
+ gtk_widget_show (GTK_WIDGET (new_composer));
}
static void
diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c
index f910f978a6..aba1fdbe9f 100644
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@ -51,22 +51,25 @@ composer_setup_charset_menu (EMsgComposer *composer)
static void
composer_setup_recent_menu (EMsgComposer *composer)
{
+ EAttachmentView *view;
GtkUIManager *manager;
GtkAction *action = NULL;
- const gchar *path, *action_name;
+ const gchar *action_name;
+ const gchar *path;
guint merge_id;
+ view = e_msg_composer_get_attachment_view (composer);
manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer));
- action_name = "recent-menu";
path = "/main-menu/insert-menu/insert-menu-top/recent-placeholder";
merge_id = gtk_ui_manager_new_merge_id (manager);
+ action_name = "recent-menu";
- action = e_attachment_bar_recent_action_new (
- e_msg_composer_get_attachment_bar (composer),
- action_name, _("Recent _Documents"));
+ action = e_attachment_view_recent_action_new (
+ view, action_name, _("Recent _Documents"));
if (action != NULL) {
- gtk_action_group_add_action (composer->priv->composer_actions, action);
+ gtk_action_group_add_action (
+ composer->priv->composer_actions, action);
gtk_ui_manager_add_ui (
manager, merge_id, path,
@@ -85,9 +88,8 @@ e_composer_private_init (EMsgComposer *composer)
GtkhtmlEditor *editor;
GtkUIManager *manager;
- GtkWidget *widget;
- GtkWidget *expander;
GtkWidget *container;
+ GtkWidget *widget;
GtkWidget *send_widget;
const gchar *path;
gchar *filename;
@@ -138,66 +140,33 @@ e_composer_private_init (EMsgComposer *composer)
/* Construct the header table. */
+ container = editor->vbox;
+
widget = e_composer_header_table_new ();
gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
- gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
- gtk_box_reorder_child (GTK_BOX (editor->vbox), widget, 2);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (container), widget, 2);
priv->header_table = g_object_ref (widget);
gtk_widget_show (widget);
- /* Construct attachment widgets.
- * XXX Move this stuff into a new custom widget. */
+ /* Construct the attachment paned. */
- widget = gtk_expander_new (NULL);
- gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
+ widget = e_attachment_paned_new ();
gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
- gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
- priv->attachment_expander = g_object_ref (widget);
- gtk_widget_show (widget);
- expander = widget;
-
- widget = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (
- GTK_SCROLLED_WINDOW (widget),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (
- GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
- gtk_container_add (GTK_CONTAINER (expander), widget);
- priv->attachment_scrolled_window = g_object_ref (widget);
- gtk_widget_show (widget);
- container = widget;
-
- widget = e_attachment_bar_new ();
- GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
- gtk_container_add (GTK_CONTAINER (container), widget);
- priv->attachment_bar = g_object_ref (widget);
- gtk_widget_show (widget);
-
- widget = gtk_hbox_new (FALSE, 0);
- gtk_expander_set_label_widget (GTK_EXPANDER (expander), widget);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->attachment_paned = g_object_ref (widget);
gtk_widget_show (widget);
- container = widget;
- widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar"));
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6);
- priv->attachment_expander_label = g_object_ref (widget);
- gtk_widget_show (widget);
+ /* Reparent the scrolled window containing the GtkHTML widget
+ * into the content area of the top attachment pane. */
- widget = gtk_image_new_from_icon_name (
- "mail-attachment", GTK_ICON_SIZE_MENU);
- gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
- gtk_widget_set_size_request (widget, 100, -1);
- gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
- priv->attachment_expander_icon = g_object_ref (widget);
- gtk_widget_hide (widget);
-
- widget = gtk_label_new (NULL);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
- gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
- priv->attachment_expander_num = g_object_ref (widget);
- gtk_widget_show (widget);
+ widget = GTK_WIDGET (gtkhtml_editor_get_html (editor));
+ widget = gtk_widget_get_parent (widget);
+ container = e_attachment_paned_get_content_area (
+ E_ATTACHMENT_PANED (priv->attachment_paned));
+ gtk_widget_reparent (widget, container);
+ gtk_box_set_child_packing (
+ GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START);
composer_setup_recent_menu (composer);
}
@@ -223,6 +192,11 @@ e_composer_private_dispose (EMsgComposer *composer)
composer->priv->header_table = NULL;
}
+ if (composer->priv->attachment_paned != NULL) {
+ g_object_unref (composer->priv->attachment_paned);
+ composer->priv->attachment_paned = NULL;
+ }
+
if (composer->priv->charset_actions != NULL) {
g_object_unref (composer->priv->charset_actions);
composer->priv->charset_actions = NULL;
diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h
index 5984d3cb2b..fc30472897 100644
--- a/composer/e-composer-private.h
+++ b/composer/e-composer-private.h
@@ -25,13 +25,14 @@
#include <camel/camel-iconv.h>
-#include "e-attachment-bar.h"
#include "e-composer-actions.h"
#include "e-composer-autosave.h"
#include "e-composer-header-table.h"
#include "e-util/e-binding.h"
#include "e-util/e-util.h"
#include "e-util/gconf-bridge.h"
+#include "widgets/misc/e-attachment-paned.h"
+#include "widgets/misc/e-attachment-store.h"
#define E_MSG_COMPOSER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -94,6 +95,8 @@ struct _EMsgComposerPrivate {
GtkWidget *html_editor;
GtkWidget *header_table;
+ GtkWidget *attachment_paned;
+
GtkActionGroup *charset_actions;
GtkActionGroup *composer_actions;
@@ -102,13 +105,6 @@ struct _EMsgComposerPrivate {
GtkWidget *focused_entry;
- GtkWidget *attachment_bar;
- GtkWidget *attachment_scrolled_window;
- GtkWidget *attachment_expander;
- GtkWidget *attachment_expander_label;
- GtkWidget *attachment_expander_icon;
- GtkWidget *attachment_expander_num;
-
GtkWidget *address_dialog;
GHashTable *inline_images;
@@ -117,7 +113,6 @@ struct _EMsgComposerPrivate {
gchar *mime_type, *mime_body, *charset;
- guint32 attachment_bar_visible : 1;
guint32 is_alternative : 1;
guint32 autosaved : 1;
guint32 mode_post : 1;
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index ab2dfc8172..138da07389 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -76,13 +76,11 @@
#include <camel/camel-smime-context.h>
#endif
-#include "mail/em-popup.h"
#include "mail/em-utils.h"
#include "mail/mail-tools.h"
#include "e-msg-composer.h"
#include "e-attachment.h"
-#include "e-attachment-bar.h"
#include "e-composer-autosave.h"
#include "e-composer-private.h"
#include "e-composer-header-table.h"
@@ -178,7 +176,6 @@ static GSList *all_composers = NULL;
static GList *add_recipients (GList *list, const gchar *recips);
static void handle_mailto (EMsgComposer *composer, const gchar *mailto);
-static void handle_uri (EMsgComposer *composer, const gchar *uri, gboolean html_dnd);
/* used by e_msg_composer_add_message_attachments () */
static void add_attachments_from_multipart (EMsgComposer *composer, CamelMultipart *multipart,
@@ -510,7 +507,8 @@ build_message (EMsgComposer *composer,
GtkhtmlEditor *editor;
EMsgComposerPrivate *p = composer->priv;
- EAttachmentBar *attachment_bar;
+ EAttachmentView *view;
+ EAttachmentStore *store;
EComposerHeaderTable *table;
GtkToggleAction *action;
CamelDataWrapper *plain, *html, *current;
@@ -538,7 +536,8 @@ build_message (EMsgComposer *composer,
editor = GTKHTML_EDITOR (composer);
table = e_msg_composer_get_header_table (composer);
account = e_composer_header_table_get_account (table);
- attachment_bar = E_ATTACHMENT_BAR (p->attachment_bar);
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
session = e_msg_composer_get_session (composer);
/* evil kludgy hack for Redirect */
@@ -699,7 +698,7 @@ build_message (EMsgComposer *composer,
} else
current = plain;
- if (e_attachment_bar_get_num_attachments (attachment_bar)) {
+ if (e_attachment_store_get_num_attachments (store) > 0) {
CamelMultipart *multipart = camel_multipart_new ();
if (p->is_alternative) {
@@ -718,7 +717,8 @@ build_message (EMsgComposer *composer,
camel_multipart_add_part (multipart, part);
camel_object_unref (part);
- e_attachment_bar_to_multipart (attachment_bar, multipart, p->charset);
+ e_attachment_store_add_to_multipart (
+ store, multipart, p->charset);
if (p->is_alternative) {
for (i = camel_multipart_get_number (multipart); i > 1; i--) {
@@ -1252,65 +1252,17 @@ autosave_load_draft (const gchar *filename)
/* Miscellaneous callbacks. */
static void
-attachment_bar_changed_cb (EAttachmentBar *attachment_bar,
- EMsgComposer *composer)
+attachment_store_changed_cb (EMsgComposer *composer)
{
GtkhtmlEditor *editor;
- GtkWidget *widget;
- guint attachment_num;
-
- editor = GTKHTML_EDITOR (composer);
- attachment_num = e_attachment_bar_get_num_attachments (attachment_bar);
-
- if (attachment_num > 0) {
- gchar *markup;
-
- markup = g_strdup_printf (
- "<b>%d</b> %s", attachment_num, ngettext (
- "Attachment", "Attachments", attachment_num));
- widget = composer->priv->attachment_expander_num;
- gtk_label_set_markup (GTK_LABEL (widget), markup);
- g_free (markup);
-
- gtk_widget_show (composer->priv->attachment_expander_icon);
-
- widget = composer->priv->attachment_expander;
- gtk_expander_set_expanded (GTK_EXPANDER (widget), TRUE);
- } else {
- widget = composer->priv->attachment_expander_num;
- gtk_label_set_text (GTK_LABEL (widget), "");
-
- gtk_widget_hide (composer->priv->attachment_expander_icon);
-
- widget = composer->priv->attachment_expander;
- gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
- }
/* Mark the editor as changed so it prompts about unsaved
changes on close. */
+ editor = GTKHTML_EDITOR (composer);
gtkhtml_editor_set_changed (editor, TRUE);
}
static void
-attachment_expander_notify_cb (GtkExpander *expander,
- GParamSpec *pspec,
- EMsgComposer *composer)
-{
- GtkLabel *label;
- const gchar *text;
-
- label = GTK_LABEL (composer->priv->attachment_expander_label);
-
- /* Update the expander label */
- if (gtk_expander_get_expanded (expander))
- text = _("Hide _Attachment Bar");
- else
- text = _("Show _Attachment Bar");
-
- gtk_label_set_text_with_mnemonic (label, text);
-}
-
-static void
msg_composer_subject_changed_cb (EMsgComposer *composer)
{
EComposerHeaderTable *table;
@@ -1505,35 +1457,6 @@ msg_composer_account_list_changed_cb (EMsgComposer *composer)
g_object_unref (iterator);
}
-static void
-msg_composer_attach_message (EMsgComposer *composer,
- CamelMimeMessage *msg)
-{
- CamelMimePart *mime_part;
- GString *description;
- const gchar *subject;
- EMsgComposerPrivate *p = composer->priv;
-
- mime_part = camel_mime_part_new ();
- camel_mime_part_set_disposition (mime_part, "inline");
- subject = camel_mime_message_get_subject (msg);
-
- description = g_string_new (_("Attached message"));
- if (subject != NULL)
- g_string_append_printf (description, " - %s", subject);
- camel_mime_part_set_description (mime_part, description->str);
- g_string_free (description, TRUE);
-
- camel_medium_set_content_object (
- (CamelMedium *) mime_part, (CamelDataWrapper *) msg);
- camel_mime_part_set_content_type (mime_part, "message/rfc822");
-
- e_attachment_bar_attach_mime_part (
- E_ATTACHMENT_BAR (p->attachment_bar), mime_part);
-
- camel_object_unref (mime_part);
-}
-
struct _drop_data {
EMsgComposer *composer;
@@ -1544,23 +1467,9 @@ struct _drop_data {
guint32 action;
guint info;
guint time;
-
- unsigned int move:1;
- unsigned int moved:1;
- unsigned int aborted:1;
};
-int
-e_msg_composer_get_remote_download_count (EMsgComposer *composer)
-{
- EAttachmentBar *attachment_bar;
-
- g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), 0);
-
- attachment_bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
- return e_attachment_bar_get_download_count (attachment_bar);
-}
-
+#if 0 /* KILL-BONOBO */
static void
drop_action (EMsgComposer *composer,
GdkDragContext *context,
@@ -1570,77 +1479,12 @@ drop_action (EMsgComposer *composer,
guint time,
gboolean html_dnd)
{
- char *tmp, *str, **urls;
CamelMimePart *mime_part;
- CamelStream *stream;
CamelMimeMessage *msg;
- char *content_type;
int i, success = FALSE, delete = FALSE;
EMsgComposerPrivate *p = composer->priv;
switch (info) {
- case DND_TYPE_MESSAGE_RFC822:
- d (printf ("dropping a message/rfc822\n"));
- /* write the message (s) out to a CamelStream so we can use it */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, (const gchar *)selection->data, selection->length);
- camel_stream_reset (stream);
-
- msg = camel_mime_message_new ();
- if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *)msg, stream) != -1) {
- msg_composer_attach_message (composer, msg);
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- }
-
- camel_object_unref (msg);
- camel_object_unref (stream);
- break;
- case DND_TYPE_NETSCAPE_URL:
- d (printf ("dropping a _NETSCAPE_URL\n"));
- tmp = g_strndup ((const gchar *) selection->data, selection->length);
- urls = g_strsplit (tmp, "\n", 2);
- g_free (tmp);
-
- /* _NETSCAPE_URL is represented as "URI\nTITLE" */
- handle_uri (composer, urls[0], html_dnd);
-
- g_strfreev (urls);
- success = TRUE;
- break;
- case DND_TYPE_TEXT_URI_LIST:
- d (printf ("dropping a text/uri-list\n"));
- tmp = g_strndup ((const gchar *) selection->data, selection->length);
- urls = g_strsplit (tmp, "\n", 0);
- g_free (tmp);
-
- for (i = 0; urls[i] != NULL; i++) {
- str = g_strstrip (urls[i]);
- if (str[0] == '#' || str[0] == '\0')
- continue;
-
- handle_uri (composer, str, html_dnd);
- }
-
- g_strfreev (urls);
- success = TRUE;
- break;
- case DND_TYPE_TEXT_VCARD:
- case DND_TYPE_TEXT_CALENDAR:
- content_type = gdk_atom_name (selection->type);
- d (printf ("dropping a %s\n", content_type));
-
- mime_part = camel_mime_part_new ();
- camel_mime_part_set_content (mime_part, (const gchar *)selection->data, selection->length, content_type);
- camel_mime_part_set_disposition (mime_part, "inline");
-
- e_attachment_bar_attach_mime_part (E_ATTACHMENT_BAR (p->attachment_bar), mime_part);
-
- camel_object_unref (mime_part);
- g_free (content_type);
-
- success = TRUE;
- break;
case DND_TYPE_X_UID_LIST: {
GPtrArray *uids;
char *inptr, *inend;
@@ -1734,55 +1578,7 @@ drop_action (EMsgComposer *composer,
gtk_drag_finish (context, success, delete, time);
}
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, gpointer data)
-{
- struct _drop_data *m = data;
-
- drop_action (
- m->composer, m->context, GDK_ACTION_COPY,
- m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, gpointer data)
-{
- struct _drop_data *m = data;
-
- drop_action (
- m->composer, m->context, GDK_ACTION_MOVE,
- m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_cancel (EPopup *ep, EPopupItem *item, gpointer data)
-{
- struct _drop_data *m = data;
-
- gtk_drag_finish (m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free (EPopup *ep, GSList *items, gpointer data)
-{
- struct _drop_data *m = data;
-
- g_slist_free (items);
-
- g_object_unref (m->context);
- g_object_unref (m->composer);
- g_free (m->selection->data);
- g_free (m->selection);
- g_free (m);
-}
+#endif
static void
msg_composer_notify_header_cb (EMsgComposer *composer)
@@ -2022,33 +1818,14 @@ msg_composer_drag_motion (GtkWidget *widget,
gint y,
guint time)
{
- GList *targets;
- GdkDragAction actions = 0;
- GdkDragAction chosen_action;
-
- targets = context->targets;
- while (targets != NULL) {
- gint ii;
-
- for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
- if (targets->data == (gpointer) drag_info[ii].atom)
- actions |= drag_info[ii].actions;
-
- targets = g_list_next (targets);
- }
-
- actions &= context->actions;
- chosen_action = context->suggested_action;
-
- /* we default to copy */
- if (chosen_action == GDK_ACTION_ASK &&
- (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) !=
- (GDK_ACTION_MOVE|GDK_ACTION_COPY))
- chosen_action = GDK_ACTION_COPY;
+ EMsgComposer *composer;
+ EAttachmentView *view;
- gdk_drag_status (context, chosen_action, time);
+ /* Widget may be EMsgComposer or GtkHTML. */
+ composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
+ view = e_msg_composer_get_attachment_view (composer);
- return (chosen_action != 0);
+ return e_attachment_view_drag_motion (view, context, x, y, time);
}
static void
@@ -2061,46 +1838,14 @@ msg_composer_drag_data_received (GtkWidget *widget,
guint time)
{
EMsgComposer *composer;
+ EAttachmentView *view;
/* Widget may be EMsgComposer or GtkHTML. */
composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
+ view = e_msg_composer_get_attachment_view (composer);
- if (selection->data == NULL)
- return;
-
- if (selection->length == -1)
- return;
-
- if (context->action == GDK_ACTION_ASK) {
- EMPopup *emp;
- GSList *menus = NULL;
- GtkMenu *menu;
- gint ii;
- struct _drop_data *m;
-
- m = g_malloc0(sizeof (*m));
- m->context = g_object_ref (context);
- m->composer = g_object_ref (composer);
- m->action = context->action;
- m->info = info;
- m->time = time;
- m->selection = g_malloc0(sizeof (*m->selection));
- m->selection->data = g_malloc (selection->length);
- memcpy (m->selection->data, selection->data, selection->length);
- m->selection->length = selection->length;
-
- emp = em_popup_new ("org.gnome.evolution.mail.composer.popup.drop");
- for (ii = 0; ii < G_N_ELEMENTS (drop_popup_menu); ii++)
- menus = g_slist_append (menus, &drop_popup_menu[ii]);
-
- e_popup_add_items ((EPopup *)emp, menus, NULL, drop_popup_free, m);
- menu = e_popup_create_menu_once ((EPopup *)emp, NULL, 0);
- gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, time);
- } else {
- drop_action (
- composer, context, context->action, selection,
- info, time, !GTK_WIDGET_TOPLEVEL (widget));
- }
+ e_attachment_view_drag_data_received (
+ view, context, x, y, selection, info, time);
}
static void
@@ -2147,11 +1892,21 @@ static void
msg_composer_paste_clipboard (GtkhtmlEditor *editor)
{
EMsgComposer *composer;
+ EAttachmentView *view;
+ EAttachmentStore *store;
+ GtkClipboard *clipboard;
+ GdkPixbuf *pixbuf;
GtkWidget *parent;
GtkWidget *widget;
- GtkClipboard *clipboard;
+ gchar *filename;
+ gchar *uri;
+ gint fd;
+ GError *error = NULL;
composer = E_MSG_COMPOSER (editor);
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
+
widget = gtk_window_get_focus (GTK_WINDOW (editor));
parent = gtk_widget_get_parent (widget);
@@ -2161,36 +1916,61 @@ msg_composer_paste_clipboard (GtkhtmlEditor *editor)
}
clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
- if (clipboard && gtk_clipboard_wait_is_image_available (clipboard)) {
- GdkPixbuf *pixbuf;
-
- pixbuf = gtk_clipboard_wait_for_image (clipboard);
- if (pixbuf) {
- char *tmpl = g_strconcat (_("Image"), "-XXXXXX", NULL);
- char *filename = e_mktemp (tmpl);
-
- g_free (tmpl);
-
- if (filename && gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL)) {
- if (gtkhtml_editor_get_html_mode (editor)) {
- char *uri = g_strconcat ("file://", filename, NULL);
- /* this loads image async, thus cannot remove file from this */
- gtkhtml_editor_insert_image (editor, uri);
- g_free (uri);
- } else {
- /* this loads image immediately, remove file from cache to free up disk space */
- e_attachment_bar_attach (E_ATTACHMENT_BAR (composer->priv->attachment_bar), filename, "image/png");
- g_remove (filename);
- }
- }
- g_free (filename);
- g_object_unref (pixbuf);
- }
- } else {
- /* Chain up to parent's paste_clipboard() method. */
- GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
+ /* Assume the clipboard has an image. The return
+ * value will be NULL if we assumed wrong. */
+ pixbuf = gtk_clipboard_wait_for_image (clipboard);
+ if (!GDK_IS_PIXBUF (pixbuf))
+ goto chainup;
+
+ /* Reserve a temporary file. */
+ fd = e_file_open_tmp (&filename, &error);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_object_unref (pixbuf);
+ g_error_free (error);
+ return;
}
+ close (fd);
+
+ /* Save the pixbuf as a temporary file in image/png format. */
+ if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) {
+ g_warning ("%s", error->message);
+ g_object_unref (pixbuf);
+ g_error_free (error);
+ g_free (filename);
+ return;
+ }
+
+ /* Convert the filename to a URI. */
+ uri = g_filename_to_uri (filename, NULL, &error);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_object_unref (pixbuf);
+ g_error_free (error);
+ g_free (filename);
+ return;
+ }
+
+ if (gtkhtml_editor_get_html_mode (editor))
+ gtkhtml_editor_insert_image (editor, uri);
+ else {
+ EAttachment *attachment;
+
+ attachment = e_attachment_new_for_uri (uri);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+ }
+
+ g_object_unref (pixbuf);
+ g_free (filename);
+ g_free (uri);
+
+ return;
+
+chainup:
+ /* Chain up to parent's paste_clipboard() method. */
+ GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
}
static void
@@ -2479,6 +2259,8 @@ msg_composer_class_init (EMsgComposerClass *class)
static void
msg_composer_init (EMsgComposer *composer)
{
+ EAttachmentView *view;
+ EAttachmentStore *store;
EComposerHeaderTable *table;
GtkUIManager *manager;
GtkhtmlEditor *editor;
@@ -2505,27 +2287,6 @@ msg_composer_init (EMsgComposer *composer)
drop_types, G_N_ELEMENTS (drop_types),
GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
- /* XXX I'm not sure why we have to explicitly configure the
- * attachment bar as a drag destination when CompEditor
- * doesn't and previous Evolution releases (2.22 and
- * prior) don't, but this is the only way I could figure
- * out how to get drag-and-drop to the attachment bar
- * working again. I'm probably overlooking something
- * simple... */
-
- gtk_drag_dest_set (
- composer->priv->attachment_bar, GTK_DEST_DEFAULT_ALL,
- drop_types, G_N_ELEMENTS (drop_types),
- GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
-
- g_signal_connect (
- composer->priv->attachment_bar, "drag-motion",
- G_CALLBACK (msg_composer_drag_motion), NULL);
-
- g_signal_connect (
- composer->priv->attachment_bar, "drag-data-received",
- G_CALLBACK (msg_composer_drag_data_received), NULL);
-
g_signal_connect (
html, "drag-data-received",
G_CALLBACK (msg_composer_drag_data_received), NULL);
@@ -2568,14 +2329,18 @@ msg_composer_init (EMsgComposer *composer)
msg_composer_account_changed_cb (composer);
msg_composer_account_list_changed_cb (composer);
- /* Attachment Bar */
+ /* Attachments */
- g_signal_connect (
- composer->priv->attachment_bar, "changed",
- G_CALLBACK (attachment_bar_changed_cb), composer);
- g_signal_connect_after (
- composer->priv->attachment_expander, "notify::expanded",
- G_CALLBACK (attachment_expander_notify_cb), composer);
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
+
+ g_signal_connect_swapped (
+ store, "row-deleted",
+ G_CALLBACK (attachment_store_changed_cb), composer);
+
+ g_signal_connect_swapped (
+ store, "row-inserted",
+ G_CALLBACK (attachment_store_changed_cb), composer);
e_composer_autosave_register (composer);
@@ -3445,7 +3210,7 @@ disable_editor (EMsgComposer *composer)
action = GTKHTML_EDITOR_ACTION_INSERT_MENU (composer);
gtk_action_set_sensitive (action, FALSE);
- gtk_widget_set_sensitive (composer->priv->attachment_bar, FALSE);
+ gtk_widget_set_sensitive (composer->priv->attachment_paned, FALSE);
}
/**
@@ -3589,7 +3354,8 @@ add_recipients (GList *list, const gchar *recips)
static void
handle_mailto (EMsgComposer *composer, const gchar *mailto)
{
- EMsgComposerPrivate *priv = composer->priv;
+ EAttachmentView *view;
+ EAttachmentStore *store;
EComposerHeaderTable *table;
GList *to = NULL, *cc = NULL, *bcc = NULL;
EDestination **tov, **ccv, **bccv;
@@ -3598,9 +3364,10 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
gsize nread, nwritten;
const gchar *p;
gint len, clen;
- CamelURL *url;
table = e_msg_composer_get_header_table (composer);
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
buf = g_strdup (mailto);
@@ -3672,20 +3439,11 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
}
} else if (!g_ascii_strcasecmp (header, "attach") ||
!g_ascii_strcasecmp (header, "attachment")) {
- /* Change file url to absolute path */
- if (!g_ascii_strncasecmp (content, "file:", 5)) {
- url = camel_url_new (content, NULL);
- e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
- url->path,
- "attachment");
- camel_url_free (url);
- } else {
- e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
- content,
- "attachment");
- }
- gtk_widget_show (priv->attachment_expander);
- gtk_widget_show (priv->attachment_scrolled_window);
+ EAttachment *attachment;
+
+ attachment = e_attachment_new_for_uri (content);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
} else if (!g_ascii_strcasecmp (header, "from")) {
/* Ignore */
} else if (!g_ascii_strcasecmp (header, "reply-to")) {
@@ -3737,45 +3495,6 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
}
}
-static void
-handle_uri (EMsgComposer *composer,
- const gchar *uri,
- gboolean html_dnd)
-{
- EMsgComposerPrivate *p = composer->priv;
- GtkhtmlEditor *editor;
- gboolean html_content;
-
- editor = GTKHTML_EDITOR (composer);
- html_content = gtkhtml_editor_get_html_mode (editor);
-
- if (!g_ascii_strncasecmp (uri, "mailto:", 7)) {
- handle_mailto (composer, uri);
- } else {
- CamelURL *url = camel_url_new (uri, NULL);
- gchar *type;
-
- if (!url)
- return;
-
- if (!g_ascii_strcasecmp (url->protocol, "file")) {
- type = e_util_guess_mime_type (uri + strlen ("file://"), TRUE);
- if (!type)
- return;
-
- if (strncmp (type, "image", 5) || !html_dnd || (!html_content && !strncmp (type, "image", 5))) {
- e_attachment_bar_attach (E_ATTACHMENT_BAR (p->attachment_bar),
- url->path, "attachment");
- }
- g_free (type);
- } else {
- e_attachment_bar_attach_remote_file (E_ATTACHMENT_BAR (p->attachment_bar),
- uri, "attachment");
- }
- camel_url_free (url);
- }
-}
-
/**
* e_msg_composer_new_from_url:
* @url: a mailto URL
@@ -3939,21 +3658,28 @@ e_msg_composer_remove_header (EMsgComposer *composer,
/**
* e_msg_composer_attach:
* @composer: a composer object
- * @attachment: the CamelMimePart to attach
+ * @mime_part: the #CamelMimePart to attach
*
* Attaches @attachment to the message being composed in the composer.
**/
void
-e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment)
+e_msg_composer_attach (EMsgComposer *composer,
+ CamelMimePart *mime_part)
{
- EAttachmentBar *bar;
- EMsgComposerPrivate *p = composer->priv;
+ EAttachmentView *view;
+ EAttachmentStore *store;
+ EAttachment *attachment;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
- g_return_if_fail (CAMEL_IS_MIME_PART (attachment));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
- bar = E_ATTACHMENT_BAR (p->attachment_bar);
- e_attachment_bar_attach_mime_part (bar, attachment);
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
}
/**
@@ -4067,12 +3793,17 @@ CamelMimeMessage *
e_msg_composer_get_message (EMsgComposer *composer,
gboolean save_html_object_data)
{
+ EAttachmentView *view;
+ EAttachmentStore *store;
GtkhtmlEditor *editor;
gboolean html_content;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
- if (e_msg_composer_get_remote_download_count (composer) != 0) {
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
+
+ if (e_attachment_store_get_num_downloading (store) > 0) {
if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL,
"mail-composer:ask-send-message-pending-download", NULL)) {
return NULL;
@@ -4367,14 +4098,6 @@ e_msg_composer_get_raw_message_text (EMsgComposer *composer)
return array;
}
-EAttachmentBar *
-e_msg_composer_get_attachment_bar (EMsgComposer *composer)
-{
- g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
-
- return E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-}
-
void
e_msg_composer_set_enable_autosave (EMsgComposer *composer,
gboolean enabled)
@@ -4529,6 +4252,18 @@ e_msg_composer_get_header_table (EMsgComposer *composer)
return E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
}
+EAttachmentView *
+e_msg_composer_get_attachment_view (EMsgComposer *composer)
+{
+ EAttachmentPaned *paned;
+
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+ paned = E_ATTACHMENT_PANED (composer->priv->attachment_paned);
+
+ return e_attachment_paned_get_view (paned);
+}
+
void
e_msg_composer_set_send_options (EMsgComposer *composer,
gboolean send_enable)
diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h
index 7e0851fb52..42f12bf973 100644
--- a/composer/e-msg-composer.h
+++ b/composer/e-msg-composer.h
@@ -29,6 +29,7 @@
#include <libedataserver/e-account.h>
#include <libebook/e-destination.h>
#include <gtkhtml-editor.h>
+#include <widgets/misc/e-attachment-view.h>
#include "e-composer-header-table.h"
@@ -66,8 +67,6 @@ struct _EMsgComposerClass {
GtkhtmlEditorClass parent_class;
};
-struct _EAttachmentBar;
-
#define E_MSG_COMPOSER_MAIL 1
#define E_MSG_COMPOSER_POST 2
#define E_MSG_COMPOSER_MAIL_POST E_MSG_COMPOSER_MAIL|E_MSG_COMPOSER_POST
@@ -104,7 +103,7 @@ void e_msg_composer_modify_header (EMsgComposer *composer,
void e_msg_composer_remove_header (EMsgComposer *composer,
const gchar *name);
void e_msg_composer_attach (EMsgComposer *composer,
- CamelMimePart *attachment);
+ CamelMimePart *mime_part);
CamelMimePart * e_msg_composer_add_inline_image_from_file
(EMsgComposer *composer,
const gchar *filename);
@@ -140,22 +139,19 @@ void e_msg_composer_add_message_attachments
gboolean e_msg_composer_request_close_all(void);
EMsgComposer * e_msg_composer_load_from_file (const gchar *filename);
void e_msg_composer_check_autosave (GtkWindow *parent);
-gint e_msg_composer_get_remote_download_count
- (EMsgComposer *composer);
void e_msg_composer_reply_indent (EMsgComposer *composer);
EComposerHeaderTable *
e_msg_composer_get_header_table (EMsgComposer *composer);
+EAttachmentView *
+ e_msg_composer_get_attachment_view
+ (EMsgComposer *composer);
void e_msg_composer_set_send_options (EMsgComposer *composer,
gboolean send_enable);
GByteArray * e_msg_composer_get_raw_message_text
(EMsgComposer *composer);
-struct _EAttachmentBar *
- e_msg_composer_get_attachment_bar
- (EMsgComposer *composer);
-
gboolean e_msg_composer_is_exiting (EMsgComposer *composer);
GList * e_load_spell_languages (void);
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index be155b52bd..eb8c2e9bd8 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -34,7 +34,7 @@ INCLUDES = \
-DSEARCH_RULE_DIR=\"$(ruledir)\" \
-DG_LOG_DOMAIN=\"e-utils\" \
$(GNOME_PILOT_CFLAGS) \
- $(ICONV_CFLAGS) \
+ $(ICONV_CFLAGS) \
$(E_UTIL_CFLAGS)
privsolib_LTLIBRARIES = libeutil.la libeconduit.la
diff --git a/e-util/e-util.c b/e-util/e-util.c
index e4e9a3ac32..02c76c3d32 100644
--- a/e-util/e-util.c
+++ b/e-util/e-util.c
@@ -1529,23 +1529,32 @@ e_util_read_file (const char *filename, gboolean filename_is_uri, char **buffer,
return res;
}
-GSList *
-e_util_get_category_filter_options (void)
+static gpointer
+e_camel_object_copy (gpointer camel_object)
{
- GSList *res = NULL;
- GList *clist, *l;
+ if (CAMEL_IS_OBJECT (camel_object))
+ camel_object_ref (camel_object);
- clist = e_categories_get_list ();
- for (l = clist; l; l = l->next) {
- const char *cname = l->data;
- struct _filter_option *fo = g_new0 (struct _filter_option, 1);
+ return camel_object;
+}
- fo->title = g_strdup (cname);
- fo->value = g_strdup (cname);
- res = g_slist_prepend (res, fo);
- }
+static void
+e_camel_object_free (gpointer camel_object)
+{
+ if (CAMEL_IS_OBJECT (camel_object))
+ camel_object_unref (camel_object);
+}
+
+GType
+e_camel_object_get_type (void)
+{
+ static GType type = 0;
- g_list_free (clist);
+ if (G_UNLIKELY (type == 0))
+ type = g_boxed_type_register_static (
+ "ECamelObject",
+ (GBoxedCopyFunc) e_camel_object_copy,
+ (GBoxedFreeFunc) e_camel_object_free);
- return g_slist_reverse (res);
+ return type;
}
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 744b4a7a9d..168b497da7 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -27,6 +27,7 @@
#include <gtk/gtk.h>
#include <limits.h>
#include <gconf/gconf-client.h>
+#include <camel/camel-object.h>
#include <cairo.h>
#include <e-util/e-marshal.h>
@@ -131,7 +132,8 @@ gboolean e_file_lock_create (void);
void e_file_lock_destroy (void);
gboolean e_file_lock_exists (void);
-gchar * e_util_guess_mime_type (const gchar *filename, gboolean localfile);
+gchar * e_util_guess_mime_type (const gchar *filename,
+ gboolean localfile);
gchar * e_util_filename_to_uri (const gchar *filename);
gchar * e_util_uri_to_filename (const gchar *uri);
@@ -141,7 +143,10 @@ gboolean e_util_read_file (const gchar *filename,
gsize *read,
GError **error);
-GSList *e_util_get_category_filter_options (void);
+/* Camel uses its own object system, so we have to box
+ * CamelObjects to safely use them as GObject properties. */
+#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ())
+GType e_camel_object_get_type (void);
G_END_DECLS
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index ac53faeffa..4088538db5 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -653,7 +653,7 @@ e_mail_browser_get_type (void)
static const GInterfaceInfo iface_info = {
(GInterfaceInitFunc) mail_browser_iface_init,
(GInterfaceFinalizeFunc) NULL,
- NULL /* interface_data */
+ NULL /* interface_data */
};
type = g_type_register_static (
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index b28221d5e9..a026f6db8d 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2009,7 +2009,7 @@ e_mail_reader_get_type (void)
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
- NULL, /* instance_init */
+ (GInstanceInitFunc) NULL,
NULL /* value_table */
};
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index 59f63adc6c..242dcdceb8 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -79,8 +79,8 @@
#include "em-icon-stream.h"
#include "em-utils.h"
#include "em-popup.h"
-#include "e-attachment.h"
-#include "e-attachment-bar.h"
+#include "widgets/misc/e-attachment-view.h"
+#include "widgets/misc/e-attachment-icon-view.h"
#ifdef G_OS_WIN32
/* Undefine the similar macro from <pthread.h>,it doesn't check if
@@ -100,7 +100,7 @@
struct _EMFormatHTMLDisplayPrivate {
/* for Attachment bar */
- GtkWidget *attachment_bar;
+ GtkWidget *attachment_view;
GtkWidget *attachment_box;
GtkWidget *label;
GtkWidget *save_txt;
@@ -494,8 +494,8 @@ efhd_format_attachment (EMFormat *emf,
info->shown = em_format_is_inline (
emf, info->puri.part_id, info->puri.part, handle);
info->snoop_mime_type = emf->snoop_mime_type;
- info->attachment = e_attachment_new_from_mime_part (info->puri.part);
- e_attachment_bar_create_attachment_cache (info->attachment);
+ info->attachment = e_attachment_new ();
+ e_attachment_set_mime_part (info->attachment, info->puri.part);
if (emf->valid) {
info->sign = emf->valid->sign.status;
@@ -559,7 +559,8 @@ efhd_format_optional (EMFormat *emf,
info->handle = em_format_find_handler (emf, "text/plain");
info->shown = FALSE;
info->snoop_mime_type = "text/plain";
- info->attachment = e_attachment_new_from_mime_part (info->puri.part);
+ info->attachment = e_attachment_new ();
+ e_attachment_set_mime_part (info->attachment, info->puri.part);
info->mstream = (CamelStreamMem *) mstream;
if (emf->valid) {
info->sign = emf->valid->sign.status;
@@ -736,12 +737,6 @@ em_format_html_display_new (void)
return g_object_new (EM_TYPE_FORMAT_HTML_DISPLAY, NULL);
}
-EAttachmentBar *
-em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd)
-{
- return E_ATTACHMENT_BAR (efhd->priv->attachment_bar);
-}
-
void
em_format_html_display_cut (EMFormatHTMLDisplay *efhd)
{
@@ -1302,6 +1297,7 @@ efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObjec
static gboolean
efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
{
+#if 0 /* KILL-BONOBO !! FIXME !! */
EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
EAttachment *new;
struct _attach_puri *info;
@@ -1324,7 +1320,10 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
return TRUE;
}
- if (efhd->priv->attachment_bar) {
+ if (efhd->priv->attachment_view) {
+ EAttachmentView *view;
+ EAttachmentStore *store;
+
file = camel_mime_part_get_filename(info->puri.part);
new = info->attachment;
@@ -1457,6 +1456,7 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
gtk_widget_hide(info->down);
gtk_container_add((GtkContainer *)eb, mainbox);
+#endif
return TRUE;
}
@@ -1500,6 +1500,7 @@ attachment_bar_arrow_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd)
static void
attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd)
{
+#if 0 /* KILL-BONOBO */
GSList *attachment_parts;
guint n_attachment_parts;
gpointer parent;
@@ -1522,31 +1523,10 @@ attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd)
attachment_parts);
g_slist_free (attachment_parts);
+#endif
}
-static void
-efhd_bar_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
- EAttachmentBar *bar = user_data;
- GnomeIconList *icon_list = user_data;
- GList *selection;
- GnomeCanvasPixbuf *image;
-
- gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
-
- selection = gnome_icon_list_get_selection (icon_list);
- if (selection == NULL)
- return;
-
- image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data));
- if (image == NULL)
- return;
-
- /* Put menu to the center of icon. */
- *x += (int)(image->item.x1 + image->item.x2) / 2;
- *y += (int)(image->item.y1 + image->item.y2) / 2;
-}
-
+#if 0 /* KILL-BONOBO -- Move this to EAttachmentView */
static void
efhd_bar_save_selected(EPopup *ep, EPopupItem *item, void *data)
{
@@ -1582,68 +1562,24 @@ static EPopupItem efhd_bar_menu_items[] = {
{ E_POPUP_BAR, "05.display", },
{ E_POPUP_ITEM, "05.display.01", N_("_Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE},
};
-
-static gboolean
-efhd_bar_button_press_event(EAttachmentBar *bar, GdkEventButton *event, EMFormat *emf)
-{
- GtkMenu *menu;
- GSList *list=NULL;
- EPopupTarget *target;
- EMPopup *emp;
- GSList *menus = NULL;
- int i;
-
- if (event && event->button != 3)
- return FALSE;
-
- /** @HookPoint-EMPopup: Attachment Bar Context Menu
- * @Id: org.gnome.evolution.mail.attachments.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetPart
- *
- * This is the drop-down menu shown when a user clicks on the attachment bar
- * when attachments are selected.
- */
- emp = em_popup_new("org.gnome.evolution.mail.attachments.popup");
-
- /* Add something like save-selected, foward selected attachments in a mail etc....*/
- list = e_attachment_bar_get_selected(bar);
-
- /* Lets not propagate any more the r-click which is intended to us*/
- if ( g_slist_length (list) == 0)
- return TRUE;
-
- target = (EPopupTarget *)em_popup_target_new_attachments(emp, list);
- for (i=0; i<2; i++)
- menus = g_slist_prepend(menus, &efhd_bar_menu_items[i]);
- e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, emf);
-
- ((EMPopupTargetPart *)target)->target.widget = (GtkWidget *)bar;
- menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
- if (event)
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
- else
- gtk_menu_popup(menu, NULL, NULL, (GtkMenuPositionFunc)efhd_bar_popup_position, bar, 0, gtk_get_current_event_time());
-
- return TRUE;
-}
-
-static gboolean
-efhd_bar_popup_menu_event (EAttachmentBar *bar, EMFormat *emf)
-{
- return efhd_bar_button_press_event(bar, NULL, emf);
-}
+#endif
static void
efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd)
{
- int nattachments;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ guint nattachments;
- if (!efhd->priv->attachment_bar)
+ if (!efhd->priv->attachment_view)
return;
- nattachments = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR(efhd->priv->attachment_bar));
- if (nattachments) {
+ view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view);
+ store = e_attachment_view_get_store (view);
+
+ nattachments = e_attachment_store_get_num_attachments (store);
+
+ if (nattachments > 0) {
char *txt;
/* Cant i put in the number of attachments here ?*/
@@ -1673,6 +1609,7 @@ efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd)
static void
efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh)
{
+#if 0 /* KILL-BONOBO -- Does EAttachmentIconView need a resize method? */
int width;
GtkRequisition req;
EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
@@ -1683,17 +1620,20 @@ efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh)
/* Update the width of the bar when the width is greater than 1*/
if (width > 0)
e_attachment_bar_set_width(E_ATTACHMENT_BAR(efhd->priv->attachment_bar), width);
+#endif
}
static gboolean
efhd_bar_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd)
{
+#if 0 /* KILL-BONOBO -- Do we still need this for a GtkIconView? */
gboolean ret;
/* Emulate the scroll over the attachment bar, as if it is scrolled in the window.
* It doesnt go automatically since the GnomeIconList is a layout by itself
*/
g_signal_emit_by_name (gtk_widget_get_parent((GtkWidget *)efhd->parent.html), "scroll_event", event, &ret);
+#endif
return TRUE;
}
@@ -1709,11 +1649,13 @@ efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd)
static gboolean
efhd_update_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
{
+#if 0 /* KILL-BONOBO -- Does EAttachmentIconView need a refresh method? */
EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv;
if (priv->attachment_bar)
e_attachment_bar_refresh (E_ATTACHMENT_BAR (priv->attachment_bar));
+#endif
return TRUE;
}
@@ -1726,10 +1668,9 @@ efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobjec
GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image, *save, *scroll;
int width, height, bar_width;
- priv->attachment_bar = e_attachment_bar_new ();
+ priv->attachment_view = e_attachment_icon_view_new ();
scroll = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- ((EAttachmentBar *)priv->attachment_bar)->expand = TRUE;
priv->forward = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
priv->down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
@@ -1759,14 +1700,14 @@ efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobjec
priv->attachment_box = scroll;
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
- gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_bar);
+ gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_view);
- gtk_widget_get_size_request(priv->attachment_bar, &width, &height);
+ gtk_widget_get_size_request(priv->attachment_view, &width, &height);
/* FIXME: What if the text is more?. Should we reduce the text with appending ...?
* or resize the bar? How to figure out that, it needs more space? */
bar_width = ((GtkWidget *)efh->html)->parent->allocation.width - /* FIXME */16;
- gtk_widget_set_size_request (priv->attachment_bar,
+ gtk_widget_set_size_request (priv->attachment_view,
bar_width > 0 ? bar_width : 0,
84 /* FIXME: Default show only one row, Dont hardcode size*/);
@@ -1782,11 +1723,8 @@ efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobjec
gtk_widget_hide_all (priv->attachment_area);
g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh);
- g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK(efhd_bar_button_press_event), efhd);
- g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK(efhd_bar_popup_menu_event), efhd);
g_signal_connect (save, "clicked", G_CALLBACK(attachments_save_all_clicked), efh);
g_signal_connect (eb, "size_allocate", G_CALLBACK (efhd_bar_resize), efh);
- g_signal_connect (priv->attachment_bar, "scroll_event", G_CALLBACK(efhd_bar_scroll_event), efhd);
return TRUE;
}
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index 2577b039e7..9cfdb03780 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -27,7 +27,6 @@
#include <camel/camel-mime-part.h>
#include <mail/em-format-html.h>
-#include <widgets/misc/e-attachment-bar.h>
/* Standard GObject macros */
#define EM_TYPE_FORMAT_HTML_DISPLAY \
@@ -76,7 +75,6 @@ void em_format_html_display_zoom_in (EMFormatHTMLDisplay *efhd);
void em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd);
void em_format_html_display_zoom_reset
(EMFormatHTMLDisplay *efhd);
-EAttachmentBar *em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd);
gboolean em_format_html_display_popup_menu
(EMFormatHTMLDisplay *efhd);
diff --git a/mail/em-popup.c b/mail/em-popup.c
index f0887f26ce..c9dde270a0 100644
--- a/mail/em-popup.c
+++ b/mail/em-popup.c
@@ -117,7 +117,9 @@ emp_class_init(GObjectClass *klass)
klass->finalize = emp_finalise;
((EPopupClass *)klass)->target_free = emp_target_free;
+#if 0 /* KILL-BONOBO */
e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL);
+#endif
}
GType
@@ -361,6 +363,7 @@ done:
return t;
}
+#if 0 /* KILL-BONOBO */
/**
* em_popup_target_new_attachments:
* @emp:
@@ -406,9 +409,11 @@ em_popup_target_new_attachments(EMPopup *emp, GSList *attachments)
return t;
}
+#endif
/* ********************************************************************** */
+#if 0 /* KILL-BONOBO */
static void
emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
{
@@ -432,7 +437,9 @@ emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
em_utils_save_part (parent, _("Save As..."), part);
}
+#endif
+#if 0 /* KILL-BONOBO */
static void
emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
{
@@ -511,6 +518,7 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
g_free(path);
}
+#endif
static void
emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data)
@@ -589,6 +597,7 @@ emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data)
em_utils_forward_message(message, NULL);
}
+#if 0 /* KILL-BONOBO */
static EMPopupItem emp_standard_object_popups[] = {
{ E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 },
{ E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE },
@@ -612,6 +621,7 @@ static EMPopupItem emp_attachment_object_popups[] = {
};
static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
+#endif
/* ********************************************************************** */
@@ -771,6 +781,7 @@ emp_add_vcard (EPopup *ep, EPopupItem *item, void *data)
camel_object_unref (mem);
}
+#if 0 /* KILL-BONOBO */
static void
emp_standard_menu_factory(EPopup *emp, void *data)
{
@@ -912,6 +923,7 @@ emp_standard_menu_factory(EPopup *emp, void *data)
if (menus)
e_popup_add_items(emp, menus, NULL, emp_standard_items_free, NULL);
}
+#endif
/* ********************************************************************** */
diff --git a/plugins/attachment-reminder/attachment-reminder.c b/plugins/attachment-reminder/attachment-reminder.c
index 15bac58080..200425041d 100644
--- a/plugins/attachment-reminder/attachment-reminder.c
+++ b/plugins/attachment-reminder/attachment-reminder.c
@@ -24,6 +24,7 @@
#include <glib/gi18n.h>
#include <string.h>
+#include <glade/glade-xml.h>
#include <gconf/gconf-client.h>
#include <e-util/e-config.h>
@@ -43,7 +44,6 @@
#include <mail/em-utils.h>
-#include "widgets/misc/e-attachment-bar.h"
#include "composer/e-msg-composer.h"
#include "composer/e-composer-actions.h"
@@ -182,12 +182,13 @@ check_for_attachment_clues (gchar *msg)
static gboolean
check_for_attachment (EMsgComposer *composer)
{
- EAttachmentBar* bar = (EAttachmentBar*)e_msg_composer_get_attachment_bar (composer);
+ EAttachmentView *view;
+ EAttachmentStore *store;
- if (e_attachment_bar_get_num_attachments (bar))
- return TRUE;
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
- return FALSE;
+ return (e_attachment_store_get_num_attachments (store) > 0);
}
static gchar*
diff --git a/plugins/import-ics-attachments/icsimporter.c b/plugins/import-ics-attachments/icsimporter.c
index fbd5e46518..096ccdec9a 100644
--- a/plugins/import-ics-attachments/icsimporter.c
+++ b/plugins/import-ics-attachments/icsimporter.c
@@ -36,7 +36,6 @@
#include <mail/em-folder-view.h>
#include <mail/em-format-html-display.h>
#include <mail/em-utils.h>
-#include "e-attachment-bar.h"
#include <camel/camel-vee-folder.h>
#include "e-util/e-error.h"
#include <libedataserverui/e-source-selector.h>
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 6e52d8bbef..5de46bcc65 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -170,12 +170,19 @@ shell_ready_for_offline (EShell *shell,
if (!is_last_ref)
return;
+ /* Increment the reference count so we can safely emit
+ * a signal without triggering the toggle reference. */
+ g_object_ref (activity);
+
e_activity_complete (activity);
g_object_remove_toggle_ref (
G_OBJECT (activity), (GToggleNotify)
shell_ready_for_offline, shell);
+ /* Finalize the activity. */
+ g_object_unref (activity);
+
shell->priv->online = FALSE;
g_object_notify (G_OBJECT (shell), "online");
@@ -217,12 +224,19 @@ shell_ready_for_online (EShell *shell,
if (!is_last_ref)
return;
+ /* Increment the reference count so we can safely emit
+ * a signal without triggering the toggle reference. */
+ g_object_ref (activity);
+
e_activity_complete (activity);
g_object_remove_toggle_ref (
G_OBJECT (activity), (GToggleNotify)
shell_ready_for_online, shell);
+ /* Finalize the activity. */
+ g_object_unref (activity);
+
shell->priv->online = TRUE;
g_object_notify (G_OBJECT (shell), "online");
diff --git a/shell/main.c b/shell/main.c
index 6b15768e07..bf0a8c47c6 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -618,13 +618,15 @@ create_default_shell (void)
shell, "window-destroyed",
G_CALLBACK (shell_window_destroyed_cb), NULL);
- g_signal_connect (
- master_client, "save_yourself",
- G_CALLBACK (master_client_save_yourself_cb), shell);
-
- g_signal_connect (
- master_client, "die",
- G_CALLBACK (master_client_die_cb), shell);
+ if (master_client != NULL) {
+ g_signal_connect (
+ master_client, "save_yourself",
+ G_CALLBACK (master_client_save_yourself_cb), shell);
+
+ g_signal_connect (
+ master_client, "die",
+ G_CALLBACK (master_client_die_cb), shell);
+ }
g_object_unref (conf_client);
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 8e79779d6d..f6fc7ed10a 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -40,8 +40,12 @@ widgetsinclude_HEADERS = \
e-activity-proxy.h \
e-alert-activity.h \
e-attachment.h \
- e-attachment-bar.h \
e-attachment-dialog.h \
+ e-attachment-icon-view.h \
+ e-attachment-paned.h \
+ e-attachment-store.h \
+ e-attachment-tree-view.h \
+ e-attachment-view.h \
e-calendar.h \
e-calendar-item.h \
e-canvas.h \
@@ -98,8 +102,12 @@ libemiscwidgets_la_SOURCES = \
e-activity-proxy.c \
e-alert-activity.c \
e-attachment.c \
- e-attachment-bar.c \
e-attachment-dialog.c \
+ e-attachment-icon-view.c \
+ e-attachment-paned.c \
+ e-attachment-store.c \
+ e-attachment-tree-view.c \
+ e-attachment-view.c \
e-calendar.c \
e-calendar-item.c \
e-canvas.c \
diff --git a/widgets/misc/e-activity.c b/widgets/misc/e-activity.c
index 352300f023..c65c3aaa0a 100644
--- a/widgets/misc/e-activity.c
+++ b/widgets/misc/e-activity.c
@@ -21,6 +21,7 @@
#include "e-activity.h"
+#include <stdarg.h>
#include <glib/gi18n.h>
#define E_ACTIVITY_GET_PRIVATE(obj) \
@@ -32,6 +33,8 @@ struct _EActivityPrivate {
gchar *primary_text;
gchar *secondary_text;
gdouble percent;
+ guint idle_id;
+ GError *error;
guint allow_cancel : 1;
guint blocking : 1;
@@ -61,6 +64,24 @@ enum {
static gpointer parent_class;
static gulong signals[LAST_SIGNAL];
+static gboolean
+activity_idle_cancel_cb (EActivity *activity)
+{
+ activity->priv->idle_id = 0;
+ e_activity_cancel (activity);
+
+ return FALSE;
+}
+
+static gboolean
+activity_idle_complete_cb (EActivity *activity)
+{
+ activity->priv->idle_id = 0;
+ e_activity_complete (activity);
+
+ return FALSE;
+}
+
static void
activity_set_property (GObject *object,
guint property_id,
@@ -178,6 +199,12 @@ activity_finalize (GObject *object)
g_free (priv->primary_text);
g_free (priv->secondary_text);
+ if (priv->idle_id > 0)
+ g_source_remove (priv->idle_id);
+
+ if (priv->error != NULL)
+ g_error_free (priv->error);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -222,12 +249,22 @@ static void
activity_cancelled (EActivity *activity)
{
activity->priv->cancelled = TRUE;
+
+ if (activity->priv->idle_id > 0) {
+ g_source_remove (activity->priv->idle_id);
+ activity->priv->idle_id = 0;
+ }
}
static void
activity_completed (EActivity *activity)
{
activity->priv->completed = TRUE;
+
+ if (activity->priv->idle_id > 0) {
+ g_source_remove (activity->priv->idle_id);
+ activity->priv->idle_id = 0;
+ }
}
static void
@@ -401,11 +438,29 @@ e_activity_new (const gchar *primary_text)
"primary-text", primary_text, NULL);
}
+EActivity *
+e_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
void
e_activity_cancel (EActivity *activity)
{
g_return_if_fail (E_IS_ACTIVITY (activity));
- g_return_if_fail (activity->priv->allow_cancel);
+
+ if (!activity->priv->allow_cancel);
+ return;
if (activity->priv->cancelled)
return;
@@ -417,6 +472,18 @@ e_activity_cancel (EActivity *activity)
}
void
+e_activity_cancel_in_idle (EActivity *activity)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (activity->priv->idle_id > 0)
+ g_source_remove (activity->priv->idle_id);
+
+ activity->priv->idle_id = g_idle_add (
+ (GSourceFunc) activity_idle_cancel_cb, activity);
+}
+
+void
e_activity_complete (EActivity *activity)
{
g_return_if_fail (E_IS_ACTIVITY (activity));
@@ -431,6 +498,18 @@ e_activity_complete (EActivity *activity)
}
void
+e_activity_complete_in_idle (EActivity *activity)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (activity->priv->idle_id > 0)
+ g_source_remove (activity->priv->idle_id);
+
+ activity->priv->idle_id = g_idle_add (
+ (GSourceFunc) activity_idle_complete_cb, activity);
+}
+
+void
e_activity_clicked (EActivity *activity)
{
g_return_if_fail (E_IS_ACTIVITY (activity));
@@ -602,3 +681,34 @@ e_activity_set_secondary_text (EActivity *activity,
g_object_notify (G_OBJECT (activity), "secondary-text");
}
+
+void
+e_activity_set_error (EActivity *activity,
+ const GError *error)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (activity->priv->error != NULL) {
+ g_error_free (activity->priv->error);
+ activity->priv->error = NULL;
+ }
+
+ if (error != NULL)
+ activity->priv->error = g_error_copy (error);
+}
+
+gboolean
+e_activity_propagate_error (EActivity *activity,
+ GError **destination)
+{
+ gboolean propagated;
+
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ if ((propagated = (activity->priv->error != NULL))) {
+ g_propagate_error (destination, activity->priv->error);
+ activity->priv->error = NULL;
+ }
+
+ return propagated;
+}
diff --git a/widgets/misc/e-activity.h b/widgets/misc/e-activity.h
index 9a14c073a0..68f0bf20be 100644
--- a/widgets/misc/e-activity.h
+++ b/widgets/misc/e-activity.h
@@ -68,8 +68,12 @@ struct _EActivityClass {
GType e_activity_get_type (void);
EActivity * e_activity_new (const gchar *primary_text);
+EActivity * e_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
void e_activity_cancel (EActivity *activity);
+void e_activity_cancel_in_idle (EActivity *activity);
void e_activity_complete (EActivity *activity);
+void e_activity_complete_in_idle (EActivity *activity);
void e_activity_clicked (EActivity *activity);
gchar * e_activity_describe (EActivity *activity);
gboolean e_activity_is_cancelled (EActivity *activity);
@@ -95,6 +99,10 @@ void e_activity_set_primary_text (EActivity *activity,
const gchar * e_activity_get_secondary_text (EActivity *activity);
void e_activity_set_secondary_text (EActivity *activity,
const gchar *secondary_text);
+void e_activity_set_error (EActivity *activity,
+ const GError *error);
+gboolean e_activity_propagate_error (EActivity *activity,
+ GError **destination);
G_END_DECLS
diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c
index 5a1a6359de..aebc6bb423 100644
--- a/widgets/misc/e-attachment-bar.c
+++ b/widgets/misc/e-attachment-bar.c
@@ -80,7 +80,6 @@
struct _EAttachmentBarPrivate {
gboolean batch_unref;
GPtrArray *attachments;
- gchar *current_folder;
char *path;
GtkUIManager *ui_manager;
@@ -89,17 +88,11 @@ struct _EAttachmentBarPrivate {
GtkActionGroup *open_actions;
guint merge_id;
- gchar *background_filename;
- gchar *background_options;
-
guint editable : 1;
};
enum {
PROP_0,
- PROP_BACKGROUND_FILENAME,
- PROP_BACKGROUND_OPTIONS,
- PROP_CURRENT_FOLDER,
PROP_EDITABLE,
PROP_UI_MANAGER
};
@@ -129,78 +122,6 @@ static const gchar *ui =
"</ui>";
static void
-action_add_cb (GtkAction *action,
- EAttachmentBar *attachment_bar)
-{
- GtkWidget *dialog;
- GtkWidget *option;
- GSList *uris, *iter;
- const gchar *disposition;
- gboolean active;
- gpointer parent;
- gint response;
-
- parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar));
- parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
- dialog = gtk_file_chooser_dialog_new (
- _("Insert Attachment"), parent,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- _("A_ttach"), GTK_RESPONSE_OK,
- NULL);
-
- gtk_dialog_set_default_response (
- GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- gtk_file_chooser_set_local_only (
- GTK_FILE_CHOOSER (dialog), FALSE);
- gtk_file_chooser_set_select_multiple (
- GTK_FILE_CHOOSER (dialog), TRUE);
- gtk_window_set_icon_name (
- GTK_WINDOW (dialog), "mail-attachment");
-
- option = gtk_check_button_new_with_mnemonic (
- _("_Suggest automatic display of attachment"));
- gtk_file_chooser_set_extra_widget (
- GTK_FILE_CHOOSER (dialog), option);
- gtk_widget_show (option);
-
- response = e_attachment_bar_file_chooser_dialog_run (
- attachment_bar, dialog);
-
- if (response != GTK_RESPONSE_OK)
- goto exit;
-
- uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
- active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
- disposition = active ? "inline" : "attachment";
-
- for (iter = uris; iter != NULL; iter = iter->next) {
- CamelURL *url;
-
- url = camel_url_new (iter->data, NULL);
- if (url == NULL)
- continue;
-
- /* XXX Do we really need two different attach functions? */
- if (g_ascii_strcasecmp (url->protocol, "file") == 0)
- e_attachment_bar_attach (
- attachment_bar, url->path, disposition);
- else
- e_attachment_bar_attach_remote_file (
- attachment_bar, iter->data, disposition);
-
- camel_url_free (url);
- }
-
- g_slist_foreach (uris, (GFunc) g_free, NULL);
- g_slist_free (uris);
-
-exit:
- gtk_widget_destroy (dialog);
-}
-
-static void
action_properties_cb (GtkAction *action,
EAttachmentBar *attachment_bar)
{
@@ -233,33 +154,6 @@ action_properties_cb (GtkAction *action,
}
static void
-action_recent_cb (GtkAction *action,
- EAttachmentBar *attachment_bar)
-{
- GtkRecentChooser *chooser;
- GFile *file;
- gchar *uri;
-
- chooser = GTK_RECENT_CHOOSER (action);
-
- /* Wish: gtk_recent_chooser_get_current_file() */
- uri = gtk_recent_chooser_get_current_uri (chooser);
- file = g_file_new_for_uri (uri);
- g_free (uri);
-
- if (g_file_is_native (file))
- e_attachment_bar_attach (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_path (file), "attachment");
- else
- e_attachment_bar_attach_remote_file (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_uri (file), "attachment");
-
- g_object_unref (file);
-}
-
-static void
action_remove_cb (GtkAction *action,
EAttachmentBar *attachment_bar)
{
@@ -409,47 +303,6 @@ action_set_background_cb (GtkAction *action,
}
}
-static GtkActionEntry standard_entries[] = {
-
- { "save-as",
- GTK_STOCK_SAVE_AS,
- NULL,
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_save_as_cb) },
-
- { "set-background",
- NULL,
- N_("Set as _Background"),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_set_background_cb) }
-};
-
-static GtkActionEntry editable_entries[] = {
-
- { "add",
- GTK_STOCK_ADD,
- N_("A_dd Attachment..."),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_add_cb) },
-
- { "properties",
- GTK_STOCK_PROPERTIES,
- NULL,
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_properties_cb) },
-
- { "remove",
- GTK_STOCK_REMOVE,
- NULL,
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_remove_cb) }
-};
-
static void
attachment_bar_show_popup_menu (EAttachmentBar *attachment_bar,
GdkEventButton *event)
@@ -950,24 +803,6 @@ attachment_bar_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_BACKGROUND_FILENAME:
- e_attachment_bar_set_background_filename (
- E_ATTACHMENT_BAR (object),
- g_value_get_string (value));
- return;
-
- case PROP_BACKGROUND_OPTIONS:
- e_attachment_bar_set_background_options (
- E_ATTACHMENT_BAR (object),
- g_value_get_string (value));
- return;
-
- case PROP_CURRENT_FOLDER:
- e_attachment_bar_set_current_folder (
- E_ATTACHMENT_BAR (object),
- g_value_get_string (value));
- return;
-
case PROP_EDITABLE:
e_attachment_bar_set_editable (
E_ATTACHMENT_BAR (object),
@@ -985,27 +820,6 @@ attachment_bar_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_BACKGROUND_FILENAME:
- g_value_set_string (
- value,
- e_attachment_bar_get_background_filename (
- E_ATTACHMENT_BAR (object)));
- return;
-
- case PROP_BACKGROUND_OPTIONS:
- g_value_set_string (
- value,
- e_attachment_bar_get_background_options (
- E_ATTACHMENT_BAR (object)));
- return;
-
- case PROP_CURRENT_FOLDER:
- g_value_set_string (
- value,
- e_attachment_bar_get_current_folder (
- E_ATTACHMENT_BAR (object)));
- return;
-
case PROP_EDITABLE:
g_value_set_boolean (
value,
@@ -1077,12 +891,8 @@ attachment_bar_finalize (GObject *object)
priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
g_ptr_array_free (priv->attachments, TRUE);
- g_free (priv->current_folder);
g_free (priv->path);
- g_free (priv->background_filename);
- g_free (priv->background_options);
-
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -1092,25 +902,13 @@ 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
@@ -1428,39 +1226,6 @@ attachment_bar_class_init (EAttachmentBarClass *class)
g_object_class_install_property (
object_class,
- PROP_BACKGROUND_FILENAME,
- g_param_spec_string (
- "background-filename",
- "Background Filename",
- NULL,
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (
- object_class,
- PROP_BACKGROUND_OPTIONS,
- g_param_spec_string (
- "background-options",
- "Background Options",
- NULL,
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (
- object_class,
- PROP_CURRENT_FOLDER,
- g_param_spec_string (
- "current-folder",
- "Current Folder",
- NULL,
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (
- object_class,
PROP_EDITABLE,
g_param_spec_boolean (
"editable",
@@ -1503,10 +1268,7 @@ static void
attachment_bar_init (EAttachmentBar *bar)
{
GnomeIconList *icon_list;
- GtkUIManager *ui_manager;
- GtkActionGroup *action_group;
gint icon_width, window_height;
- const gchar *domain = GETTEXT_PACKAGE;
GError *error = NULL;
bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
@@ -1532,38 +1294,6 @@ attachment_bar_init (EAttachmentBar *bar)
gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
- ui_manager = gtk_ui_manager_new ();
- bar->priv->ui_manager = ui_manager;
- bar->priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
-
- action_group = gtk_action_group_new ("standard");
- gtk_action_group_set_translation_domain (action_group, domain);
- gtk_action_group_add_actions (
- action_group, standard_entries,
- G_N_ELEMENTS (standard_entries), bar);
- gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
- bar->priv->standard_actions = action_group;
-
- action_group = gtk_action_group_new ("editable");
- gtk_action_group_set_translation_domain (action_group, domain);
- gtk_action_group_add_actions (
- action_group, editable_entries,
- G_N_ELEMENTS (editable_entries), bar);
- gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
- bar->priv->editable_actions = action_group;
-
- action_group = gtk_action_group_new ("open");
- gtk_action_group_set_translation_domain (action_group, domain);
- gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
- bar->priv->open_actions = action_group;
-
- /* Because we are loading from a hard-coded string, there is
- * no chance of I/O errors. Failure here imples a malformed
- * UI definition. Full stop. */
- gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
- if (error != NULL)
- g_error ("%s", error->message);
}
GType
@@ -2038,69 +1768,6 @@ e_attachment_bar_attach_mime_part (EAttachmentBar *bar,
e_attachment_bar_add_attachment (bar, attachment);
}
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
- const gchar *action_name,
- const gchar *action_label)
-{
- GtkAction *action;
- GtkRecentChooser *chooser;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- action = gtk_recent_action_new (
- action_name, action_label, NULL, NULL);
- gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
-
- chooser = GTK_RECENT_CHOOSER (action);
- gtk_recent_chooser_set_show_icons (chooser, TRUE);
- gtk_recent_chooser_set_show_not_found (chooser, FALSE);
- gtk_recent_chooser_set_show_private (chooser, FALSE);
- gtk_recent_chooser_set_show_tips (chooser, TRUE);
- gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
-
- g_signal_connect (
- action, "item-activated",
- G_CALLBACK (action_recent_cb), bar);
-
- return action;
-}
-
-gint
-e_attachment_bar_file_chooser_dialog_run (EAttachmentBar *attachment_bar,
- GtkWidget *dialog)
-{
- GtkFileChooser *file_chooser;
- gint response = GTK_RESPONSE_NONE;
- const gchar *current_folder;
- gboolean save_folder;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), response);
- g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
-
- file_chooser = GTK_FILE_CHOOSER (dialog);
- current_folder = e_attachment_bar_get_current_folder (attachment_bar);
- gtk_file_chooser_set_current_folder (file_chooser, current_folder);
-
- response = gtk_dialog_run (GTK_DIALOG (dialog));
-
- save_folder =
- (response == GTK_RESPONSE_ACCEPT) ||
- (response == GTK_RESPONSE_OK) ||
- (response == GTK_RESPONSE_YES) ||
- (response == GTK_RESPONSE_APPLY);
-
- if (save_folder) {
- gchar *folder;
-
- folder = gtk_file_chooser_get_current_folder (file_chooser);
- e_attachment_bar_set_current_folder (attachment_bar, folder);
- g_free (folder);
- }
-
- return response;
-}
-
void
e_attachment_bar_update_actions (EAttachmentBar *attachment_bar)
{
@@ -2109,82 +1776,6 @@ e_attachment_bar_update_actions (EAttachmentBar *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)
{
@@ -2203,39 +1794,3 @@ e_attachment_bar_set_editable (EAttachmentBar *attachment_bar,
g_object_notify (G_OBJECT (attachment_bar), "editable");
}
-
-GtkUIManager *
-e_attachment_bar_get_ui_manager (EAttachmentBar *attachment_bar)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
-
- return attachment_bar->priv->ui_manager;
-}
-
-GtkAction *
-e_attachment_bar_get_action (EAttachmentBar *attachment_bar,
- const gchar *action_name)
-{
- GtkUIManager *ui_manager;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
- g_return_val_if_fail (action_name != NULL, NULL);
-
- ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
-
- return e_lookup_action (ui_manager, action_name);
-}
-
-GtkActionGroup *
-e_attachment_bar_get_action_group (EAttachmentBar *attachment_bar,
- const gchar *group_name)
-{
- GtkUIManager *ui_manager;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
- g_return_val_if_fail (group_name != NULL, NULL);
-
- ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
-
- return e_lookup_action_group (ui_manager, group_name);
-}
diff --git a/widgets/misc/e-attachment-dialog.c b/widgets/misc/e-attachment-dialog.c
index 0668a7358d..f697df1fe9 100644
--- a/widgets/misc/e-attachment-dialog.c
+++ b/widgets/misc/e-attachment-dialog.c
@@ -29,9 +29,9 @@
struct _EAttachmentDialogPrivate {
EAttachment *attachment;
- GtkWidget *filename_entry;
+ GtkWidget *display_name_entry;
GtkWidget *description_entry;
- GtkWidget *mime_type_label;
+ GtkWidget *content_type_label;
GtkWidget *disposition_checkbox;
};
@@ -46,56 +46,54 @@ static void
attachment_dialog_update (EAttachmentDialog *dialog)
{
EAttachment *attachment;
- CamelMimePart *mime_part;
+ GFileInfo *file_info;
GtkWidget *widget;
+ const gchar *content_type;
+ const gchar *display_name;
+ const gchar *description;
+ const gchar *disposition;
gboolean sensitive;
- const gchar *text;
gboolean active;
- /* XXX This is too complex. I shouldn't have to use the
- * MIME part at all. */
-
attachment = e_attachment_dialog_get_attachment (dialog);
- if (attachment != NULL)
- mime_part = e_attachment_get_mime_part (attachment);
- else
- mime_part = NULL;
- sensitive = (attachment != NULL);
+ if (E_IS_ATTACHMENT (attachment)) {
+ file_info = e_attachment_get_file_info (attachment);
+ content_type = e_attachment_get_content_type (attachment);
+ display_name = e_attachment_get_display_name (attachment);
+ description = e_attachment_get_description (attachment);
+ disposition = e_attachment_get_disposition (attachment);
+ } else {
+ file_info = NULL;
+ content_type = NULL;
+ display_name = NULL;
+ description = NULL;
+ disposition = NULL;
+ }
+
+ sensitive = G_IS_FILE_INFO (file_info);
+
gtk_dialog_set_response_sensitive (
GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
- text = NULL;
- if (attachment != NULL)
- text = e_attachment_get_filename (attachment);
- text = (text != NULL) ? text : "";
- widget = dialog->priv->filename_entry;
+ if (display_name == NULL)
+ display_name = "";
+ widget = dialog->priv->display_name_entry;
gtk_widget_set_sensitive (widget, sensitive);
- gtk_entry_set_text (GTK_ENTRY (widget), text);
+ gtk_entry_set_text (GTK_ENTRY (widget), display_name);
- text = NULL;
- if (attachment != NULL)
- text = e_attachment_get_description (attachment);
- text = (text != NULL) ? text : "";
+ if (description == NULL)
+ description = "";
widget = dialog->priv->description_entry;
gtk_widget_set_sensitive (widget, sensitive);
- gtk_entry_set_text (GTK_ENTRY (widget), text);
+ gtk_entry_set_text (GTK_ENTRY (widget), description);
- text = NULL;
- if (attachment != NULL)
- text = e_attachment_get_mime_type (attachment);
- text = (text != NULL) ? text : "";
- widget = dialog->priv->mime_type_label;
- gtk_label_set_text (GTK_LABEL (widget), text);
-
- active = FALSE;
- if (mime_part != NULL) {
- const gchar *disposition;
-
- disposition = camel_mime_part_get_disposition (mime_part);
- active = (g_ascii_strcasecmp (disposition, "inline") == 0);
- } else if (attachment != NULL)
- active = e_attachment_is_inline (attachment);
+ if (content_type == NULL)
+ content_type = "";
+ widget = dialog->priv->content_type_label;
+ gtk_label_set_text (GTK_LABEL (widget), content_type);
+
+ active = (g_strcmp0 (disposition, "inline") == 0);
widget = dialog->priv->disposition_checkbox;
gtk_widget_set_sensitive (widget, sensitive);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
@@ -147,9 +145,9 @@ attachment_dialog_dispose (GObject *object)
priv->attachment = NULL;
}
- if (priv->filename_entry != NULL) {
- g_object_unref (priv->filename_entry);
- priv->filename_entry = NULL;
+ if (priv->display_name_entry != NULL) {
+ g_object_unref (priv->display_name_entry);
+ priv->display_name_entry = NULL;
}
if (priv->description_entry != NULL) {
@@ -157,9 +155,9 @@ attachment_dialog_dispose (GObject *object)
priv->description_entry = NULL;
}
- if (priv->mime_type_label != NULL) {
- g_object_unref (priv->mime_type_label);
- priv->mime_type_label = NULL;
+ if (priv->content_type_label != NULL) {
+ g_object_unref (priv->content_type_label);
+ priv->content_type_label = NULL;
}
if (priv->disposition_checkbox != NULL) {
@@ -196,7 +194,8 @@ attachment_dialog_response (GtkDialog *dialog,
EAttachmentDialogPrivate *priv;
EAttachment *attachment;
GtkToggleButton *button;
- GtkEntry *entry;
+ GFileInfo *file_info;
+ const gchar *attribute;
const gchar *text;
gboolean active;
@@ -204,16 +203,19 @@ attachment_dialog_response (GtkDialog *dialog,
return;
priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
- g_return_if_fail (priv->attachment != NULL);
+ g_return_if_fail (E_IS_ATTACHMENT (priv->attachment));
attachment = priv->attachment;
- entry = GTK_ENTRY (priv->filename_entry);
- text = gtk_entry_get_text (entry);
- e_attachment_set_filename (attachment, text);
+ file_info = e_attachment_get_file_info (attachment);
+ g_return_if_fail (G_IS_FILE_INFO (file_info));
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+ text = gtk_entry_get_text (GTK_ENTRY (priv->display_name_entry));
+ g_file_info_set_attribute_string (file_info, attribute, text);
- entry = GTK_ENTRY (priv->description_entry);
- text = gtk_entry_get_text (entry);
- e_attachment_set_description (attachment, text);
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ text = gtk_entry_get_text (GTK_ENTRY (priv->description_entry));
+ g_file_info_set_attribute_string (file_info, attribute, text);
button = GTK_TOGGLE_BUTTON (priv->disposition_checkbox);
active = gtk_toggle_button_get_active (button);
@@ -289,13 +291,13 @@ attachment_dialog_init (EAttachmentDialog *dialog)
gtk_table_attach (
GTK_TABLE (container), widget,
1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
- dialog->priv->filename_entry = g_object_ref (widget);
+ dialog->priv->display_name_entry = g_object_ref (widget);
gtk_widget_show (widget);
widget = gtk_label_new_with_mnemonic (_("_Filename:"));
gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
gtk_label_set_mnemonic_widget (
- GTK_LABEL (widget), dialog->priv->filename_entry);
+ GTK_LABEL (widget), dialog->priv->display_name_entry);
gtk_table_attach (
GTK_TABLE (container), widget,
0, 1, 0, 1, GTK_FILL, 0, 0, 0);
@@ -324,7 +326,7 @@ attachment_dialog_init (EAttachmentDialog *dialog)
gtk_table_attach (
GTK_TABLE (container), widget,
1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
- dialog->priv->mime_type_label = g_object_ref (widget);
+ dialog->priv->content_type_label = g_object_ref (widget);
gtk_widget_show (widget);
widget = gtk_label_new (_("MIME Type:"));
diff --git a/widgets/misc/e-attachment-icon-view.c b/widgets/misc/e-attachment-icon-view.c
new file mode 100644
index 0000000000..8d39a76d75
--- /dev/null
+++ b/widgets/misc/e-attachment-icon-view.c
@@ -0,0 +1,319 @@
+/*
+ * e-attachment-icon-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-icon-view.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "e-attachment.h"
+#include "e-attachment-store.h"
+#include "e-attachment-view.h"
+
+#define E_ATTACHMENT_ICON_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconViewPrivate))
+
+struct _EAttachmentIconViewPrivate {
+ EAttachmentViewPrivate view_priv;
+};
+
+static gpointer parent_class;
+
+static void
+attachment_icon_view_dispose (GObject *object)
+{
+ e_attachment_view_dispose (E_ATTACHMENT_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_icon_view_finalize (GObject *object)
+{
+ e_attachment_view_finalize (E_ATTACHMENT_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+attachment_icon_view_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+ e_attachment_view_show_popup_menu (view, event);
+ return TRUE;
+ }
+
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_press_event (widget, event);
+}
+
+static gboolean
+attachment_icon_view_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ if (event->keyval == GDK_Delete) {
+ e_attachment_view_remove_selected (view, TRUE);
+ return TRUE;
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ key_press_event (widget, event);
+}
+
+static gboolean
+attachment_icon_view_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+attachment_icon_view_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ e_attachment_view_drag_data_received (
+ view, context, x, y, selection, info, time);
+}
+
+static gboolean
+attachment_icon_view_popup_menu (GtkWidget *widget)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ e_attachment_view_show_popup_menu (view, NULL);
+
+ return TRUE;
+}
+
+static EAttachmentViewPrivate *
+attachment_icon_view_get_private (EAttachmentView *view)
+{
+ EAttachmentIconViewPrivate *priv;
+
+ priv = E_ATTACHMENT_ICON_VIEW_GET_PRIVATE (view);
+
+ return &priv->view_priv;
+}
+
+static EAttachmentStore *
+attachment_icon_view_get_store (EAttachmentView *view)
+{
+ GtkIconView *icon_view;
+ GtkTreeModel *model;
+
+ icon_view = GTK_ICON_VIEW (view);
+ model = gtk_icon_view_get_model (icon_view);
+
+ return E_ATTACHMENT_STORE (model);
+}
+
+static GtkTreePath *
+attachment_icon_view_get_path_at_pos (EAttachmentView *view,
+ gint x,
+ gint y)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ return gtk_icon_view_get_path_at_pos (icon_view, x, y);
+}
+
+static GList *
+attachment_icon_view_get_selected_paths (EAttachmentView *view)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ return gtk_icon_view_get_selected_items (icon_view);
+}
+
+static gboolean
+attachment_icon_view_path_is_selected (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ return gtk_icon_view_path_is_selected (icon_view, path);
+}
+
+static void
+attachment_icon_view_select_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ gtk_icon_view_select_path (icon_view, path);
+}
+
+static void
+attachment_icon_view_unselect_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ gtk_icon_view_unselect_path (icon_view, path);
+}
+
+static void
+attachment_icon_view_select_all (EAttachmentView *view)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ gtk_icon_view_select_all (icon_view);
+}
+
+static void
+attachment_icon_view_unselect_all (EAttachmentView *view)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (view);
+
+ gtk_icon_view_unselect_all (icon_view);
+}
+
+static void
+attachment_icon_view_class_init (EAttachmentIconViewClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = attachment_icon_view_dispose;
+ object_class->finalize = attachment_icon_view_finalize;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->button_press_event = attachment_icon_view_button_press_event;
+ widget_class->key_press_event = attachment_icon_view_key_press_event;
+ widget_class->drag_motion = attachment_icon_view_drag_motion;
+ widget_class->drag_data_received = attachment_icon_view_drag_data_received;
+ widget_class->popup_menu = attachment_icon_view_popup_menu;
+}
+
+static void
+attachment_icon_view_iface_init (EAttachmentViewIface *iface)
+{
+ iface->get_private = attachment_icon_view_get_private;
+ iface->get_store = attachment_icon_view_get_store;
+
+ iface->get_path_at_pos = attachment_icon_view_get_path_at_pos;
+ iface->get_selected_paths = attachment_icon_view_get_selected_paths;
+ iface->path_is_selected = attachment_icon_view_path_is_selected;
+ iface->select_path = attachment_icon_view_select_path;
+ iface->unselect_path = attachment_icon_view_unselect_path;
+ iface->select_all = attachment_icon_view_select_all;
+ iface->unselect_all = attachment_icon_view_unselect_all;
+}
+
+static void
+attachment_icon_view_init (EAttachmentIconView *icon_view)
+{
+ icon_view->priv = E_ATTACHMENT_ICON_VIEW_GET_PRIVATE (icon_view);
+
+ e_attachment_view_init (E_ATTACHMENT_VIEW (icon_view));
+
+ gtk_icon_view_set_selection_mode (
+ GTK_ICON_VIEW (icon_view), GTK_SELECTION_MULTIPLE);
+
+ gtk_icon_view_set_pixbuf_column (
+ GTK_ICON_VIEW (icon_view),
+ E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF);
+
+ gtk_icon_view_set_text_column (
+ GTK_ICON_VIEW (icon_view),
+ E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION);
+}
+
+GType
+e_attachment_icon_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentIconViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_icon_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAttachmentIconView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_icon_view_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) attachment_icon_view_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_ICON_VIEW, "EAttachmentIconView",
+ &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_ATTACHMENT_VIEW, &iface_info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_attachment_icon_view_new (void)
+{
+ return g_object_new (E_TYPE_ATTACHMENT_ICON_VIEW, NULL);
+}
diff --git a/widgets/misc/e-attachment-icon-view.h b/widgets/misc/e-attachment-icon-view.h
new file mode 100644
index 0000000000..ab9360e42e
--- /dev/null
+++ b/widgets/misc/e-attachment-icon-view.h
@@ -0,0 +1,66 @@
+/*
+ * e-attachment-icon-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_ICON_VIEW_H
+#define E_ATTACHMENT_ICON_VIEW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_ICON_VIEW \
+ (e_attachment_icon_view_get_type ())
+#define E_ATTACHMENT_ICON_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconView))
+#define E_ATTACHMENT_ICON_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_ICON_VIEW, EAttachmentIconView))
+#define E_IS_ATTACHMENT_ICON_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_ICON_VIEW))
+#define E_IS_ATTACHMENT_ICON_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_ICON_VIEW))
+#define E_ATTACHMENT_ICON_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_ICON_VIEW))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentIconView EAttachmentIconView;
+typedef struct _EAttachmentIconViewClass EAttachmentIconViewClass;
+typedef struct _EAttachmentIconViewPrivate EAttachmentIconViewPrivate;
+
+struct _EAttachmentIconView {
+ GtkIconView parent;
+ EAttachmentIconViewPrivate *priv;
+};
+
+struct _EAttachmentIconViewClass {
+ GtkIconViewClass parent_class;
+};
+
+GType e_attachment_icon_view_get_type (void);
+GtkWidget * e_attachment_icon_view_new (void);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_ICON_VIEW_H */
diff --git a/widgets/misc/e-attachment-paned.c b/widgets/misc/e-attachment-paned.c
new file mode 100644
index 0000000000..bb919e9789
--- /dev/null
+++ b/widgets/misc/e-attachment-paned.c
@@ -0,0 +1,563 @@
+/*
+ * e-attachment-paned.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-paned.h"
+
+#include <glib/gi18n.h>
+#include "e-util/e-binding.h"
+#include "e-attachment-store.h"
+#include "e-attachment-icon-view.h"
+#include "e-attachment-tree-view.h"
+
+#define E_ATTACHMENT_PANED_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedPrivate))
+
+#define NUM_VIEWS 2
+
+struct _EAttachmentPanedPrivate {
+ GtkTreeModel *model;
+ GtkWidget *expander;
+ GtkWidget *notebook;
+ GtkWidget *combo_box;
+ GtkWidget *icon_view;
+ GtkWidget *tree_view;
+ GtkWidget *show_hide_label;
+ GtkWidget *status_icon;
+ GtkWidget *status_label;
+ GtkWidget *content_area;
+
+ gint active_view;
+ guint expanded : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_ACTIVE_VIEW,
+ PROP_EXPANDED
+};
+
+static gpointer parent_class;
+
+static void
+attachment_paned_notify_cb (EAttachmentPaned *paned,
+ GParamSpec *pspec,
+ GtkExpander *expander)
+{
+ GtkLabel *label;
+ const gchar *text;
+
+ label = GTK_LABEL (paned->priv->show_hide_label);
+
+ /* Update the expander label. */
+ if (gtk_expander_get_expanded (expander))
+ text = _("Hide _Attachment Bar");
+ else
+ text = _("Show _Attachment Bar");
+
+ gtk_label_set_text_with_mnemonic (label, text);
+}
+
+static void
+attachment_paned_sync_icon_view (EAttachmentPaned *paned)
+{
+ EAttachmentView *source;
+ EAttachmentView *target;
+
+ source = E_ATTACHMENT_VIEW (paned->priv->tree_view);
+ target = E_ATTACHMENT_VIEW (paned->priv->icon_view);
+
+ /* Only sync if the tree view is active. This prevents the
+ * two views from endlessly trying to sync with each other. */
+ if (e_attachment_paned_get_active_view (paned) == 1)
+ e_attachment_view_sync_selection (source, target);
+}
+
+static void
+attachment_paned_sync_tree_view (EAttachmentPaned *paned)
+{
+ EAttachmentView *source;
+ EAttachmentView *target;
+
+ source = E_ATTACHMENT_VIEW (paned->priv->icon_view);
+ target = E_ATTACHMENT_VIEW (paned->priv->tree_view);
+
+ /* Only sync if the icon view is active. This prevents the
+ * two views from endlessly trying to sync with each other. */
+ if (e_attachment_paned_get_active_view (paned) == 0)
+ e_attachment_view_sync_selection (source, target);
+}
+
+static void
+attachment_paned_update_status (EAttachmentPaned *paned)
+{
+ EAttachmentView *view;
+ EAttachmentStore *store;
+ GtkExpander *expander;
+ GtkLabel *label;
+ guint num_attachments;
+ guint64 total_size;
+ gchar *display_size;
+ gchar *markup;
+
+ view = e_attachment_paned_get_view (paned);
+ store = e_attachment_view_get_store (view);
+ expander = GTK_EXPANDER (paned->priv->expander);
+ label = GTK_LABEL (paned->priv->status_label);
+
+ num_attachments = e_attachment_store_get_num_attachments (store);
+ total_size = e_attachment_store_get_total_size (store);
+ display_size = g_format_size_for_display (total_size);
+
+ markup = g_strdup_printf (
+ "<b>%d</b> %s (%s)", num_attachments, ngettext (
+ "Attachment", "Attachments", num_attachments),
+ display_size);
+ gtk_label_set_markup (label, markup);
+ g_free (markup);
+
+ g_free (display_size);
+
+ if (num_attachments > 0) {
+ gtk_widget_show (paned->priv->status_icon);
+ gtk_widget_show (paned->priv->status_label);
+ gtk_expander_set_expanded (expander, TRUE);
+ } else {
+ gtk_widget_hide (paned->priv->status_icon);
+ gtk_widget_hide (paned->priv->status_label);
+ gtk_expander_set_expanded (expander, FALSE);
+ }
+}
+
+static void
+attachment_paned_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVE_VIEW:
+ e_attachment_paned_set_active_view (
+ E_ATTACHMENT_PANED (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_EXPANDED:
+ e_attachment_paned_set_expanded (
+ E_ATTACHMENT_PANED (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_paned_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVE_VIEW:
+ g_value_set_int (
+ value, e_attachment_paned_get_active_view (
+ E_ATTACHMENT_PANED (object)));
+ return;
+
+ case PROP_EXPANDED:
+ g_value_set_boolean (
+ value, e_attachment_paned_get_expanded (
+ E_ATTACHMENT_PANED (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_paned_dispose (GObject *object)
+{
+ EAttachmentPanedPrivate *priv;
+
+ priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
+
+ if (priv->model != NULL) {
+ g_object_unref (priv->model);
+ priv->model = NULL;
+ }
+
+ if (priv->expander != NULL) {
+ g_object_unref (priv->expander);
+ priv->expander = NULL;
+ }
+
+ if (priv->notebook != NULL) {
+ g_object_unref (priv->notebook);
+ priv->notebook = NULL;
+ }
+
+ if (priv->combo_box != NULL) {
+ g_object_unref (priv->combo_box);
+ priv->combo_box = NULL;
+ }
+
+ if (priv->icon_view != NULL) {
+ g_object_unref (priv->icon_view);
+ priv->icon_view = NULL;
+ }
+
+ if (priv->tree_view != NULL) {
+ g_object_unref (priv->tree_view);
+ priv->tree_view = NULL;
+ }
+
+ if (priv->show_hide_label != NULL) {
+ g_object_unref (priv->show_hide_label);
+ priv->show_hide_label = NULL;
+ }
+
+ if (priv->status_icon != NULL) {
+ g_object_unref (priv->status_icon);
+ priv->status_icon = NULL;
+ }
+
+ if (priv->status_label != NULL) {
+ g_object_unref (priv->status_label);
+ priv->status_label = NULL;
+ }
+
+ if (priv->content_area != NULL) {
+ g_object_unref (priv->content_area);
+ priv->content_area = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_paned_constructed (GObject *object)
+{
+ EAttachmentPanedPrivate *priv;
+
+ priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "active-view",
+ G_OBJECT (priv->combo_box), "active");
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "active-view",
+ G_OBJECT (priv->notebook), "page");
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "expanded",
+ G_OBJECT (priv->expander), "expanded");
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "expanded",
+ G_OBJECT (priv->combo_box), "sensitive");
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "expanded",
+ G_OBJECT (priv->notebook), "visible");
+}
+
+static void
+attachment_paned_class_init (EAttachmentPanedClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentPanedPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_paned_set_property;
+ object_class->get_property = attachment_paned_get_property;
+ object_class->dispose = attachment_paned_dispose;
+ object_class->constructed = attachment_paned_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACTIVE_VIEW,
+ g_param_spec_int (
+ "active-view",
+ "Active View",
+ NULL,
+ 0,
+ NUM_VIEWS,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EXPANDED,
+ g_param_spec_boolean (
+ "expanded",
+ "Expanded",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_paned_init (EAttachmentPaned *paned)
+{
+ GtkTreeSelection *selection;
+ GtkSizeGroup *size_group;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ paned->priv = E_ATTACHMENT_PANED_GET_PRIVATE (paned);
+ paned->priv->model = e_attachment_store_new ();
+
+ /* Keep the expander label and combo box the same height. */
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+
+ /* Construct the Controls */
+
+ container = GTK_WIDGET (paned);
+
+ widget = gtk_vbox_new (FALSE, 6);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+ paned->priv->content_area = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_expander_new (NULL);
+ gtk_expander_set_spacing (GTK_EXPANDER (widget), 0);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ paned->priv->expander = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_combo_box_new_text ();
+ gtk_size_group_add_widget (size_group, widget);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Icon View"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("List View"));
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ paned->priv->combo_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = paned->priv->expander;
+
+ widget = gtk_hbox_new (FALSE, 0);
+ gtk_size_group_add_widget (size_group, widget);
+ gtk_expander_set_label_widget (GTK_EXPANDER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6);
+ paned->priv->show_hide_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_image_new_from_icon_name (
+ "mail-attachment", GTK_ICON_SIZE_MENU);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_widget_set_size_request (widget, 100, -1);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ paned->priv->status_icon = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ widget = gtk_label_new (NULL);
+ gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
+ paned->priv->status_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Construct the Attachment Views */
+
+ container = GTK_WIDGET (paned);
+
+ widget = gtk_notebook_new ();
+ gtk_widget_set_size_request (widget, -1, 40);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, FALSE);
+ paned->priv->notebook = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ container = paned->priv->notebook;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_attachment_icon_view_new ();
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+ gtk_icon_view_set_model (GTK_ICON_VIEW (widget), paned->priv->model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ paned->priv->icon_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = paned->priv->notebook;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_attachment_tree_view_new ();
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (widget), paned->priv->model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ paned->priv->tree_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (paned->priv->tree_view));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (attachment_paned_sync_icon_view), paned);
+
+ g_signal_connect_swapped (
+ paned->priv->icon_view, "selection-changed",
+ G_CALLBACK (attachment_paned_sync_tree_view), paned);
+
+ g_signal_connect_swapped (
+ paned->priv->expander, "notify::expanded",
+ G_CALLBACK (attachment_paned_notify_cb), paned);
+
+ g_signal_connect_swapped (
+ paned->priv->model, "notify::num-attachments",
+ G_CALLBACK (attachment_paned_update_status), paned);
+
+ g_signal_connect_swapped (
+ paned->priv->model, "notify::total-size",
+ G_CALLBACK (attachment_paned_update_status), paned);
+
+ g_object_unref (size_group);
+}
+
+GType
+e_attachment_paned_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentPanedClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_paned_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAttachmentPaned),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_paned_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_VPANED, "EAttachmentPaned",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_attachment_paned_new (void)
+{
+ return g_object_new (E_TYPE_ATTACHMENT_PANED, NULL);
+}
+
+EAttachmentView *
+e_attachment_paned_get_view (EAttachmentPaned *paned)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL);
+
+ return E_ATTACHMENT_VIEW (paned->priv->icon_view);
+}
+
+GtkWidget *
+e_attachment_paned_get_content_area (EAttachmentPaned *paned)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL);
+
+ return paned->priv->content_area;
+}
+
+gint
+e_attachment_paned_get_active_view (EAttachmentPaned *paned)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), 0);
+
+ return paned->priv->active_view;
+}
+
+void
+e_attachment_paned_set_active_view (EAttachmentPaned *paned,
+ gint active_view)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
+ g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS);
+
+ paned->priv->active_view = active_view;
+
+ g_object_notify (G_OBJECT (paned), "active-view");
+}
+
+gboolean
+e_attachment_paned_get_expanded (EAttachmentPaned *paned)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), FALSE);
+
+ return paned->priv->expanded;
+}
+
+void
+e_attachment_paned_set_expanded (EAttachmentPaned *paned,
+ gboolean expanded)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
+
+ paned->priv->expanded = expanded;
+
+ g_object_notify (G_OBJECT (paned), "expanded");
+}
diff --git a/widgets/misc/e-attachment-paned.h b/widgets/misc/e-attachment-paned.h
new file mode 100644
index 0000000000..c6cad5226f
--- /dev/null
+++ b/widgets/misc/e-attachment-paned.h
@@ -0,0 +1,79 @@
+/*
+ * e-attachment-paned.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_PANED_H
+#define E_ATTACHMENT_PANED_H
+
+#include <gtk/gtk.h>
+#include <e-attachment-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_PANED \
+ (e_attachment_paned_get_type ())
+#define E_ATTACHMENT_PANED(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPaned))
+#define E_ATTACHMENT_PANED_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedClass))
+#define E_IS_ATTACHMENT_PANED(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_PANED))
+#define E_IS_ATTACHMENT_PANED_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_PANED))
+#define E_ATTACHMENT_PANED_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentPaned EAttachmentPaned;
+typedef struct _EAttachmentPanedClass EAttachmentPanedClass;
+typedef struct _EAttachmentPanedPrivate EAttachmentPanedPrivate;
+
+struct _EAttachmentPaned {
+ GtkVPaned parent;
+ EAttachmentPanedPrivate *priv;
+};
+
+struct _EAttachmentPanedClass {
+ GtkVPanedClass parent_class;
+};
+
+GType e_attachment_paned_get_type (void);
+GtkWidget * e_attachment_paned_new (void);
+EAttachmentView *
+ e_attachment_paned_get_view (EAttachmentPaned *paned);
+GtkWidget * e_attachment_paned_get_content_area
+ (EAttachmentPaned *paned);
+gint e_attachment_paned_get_active_view
+ (EAttachmentPaned *paned);
+void e_attachment_paned_set_active_view
+ (EAttachmentPaned *paned,
+ gint active_view);
+gboolean e_attachment_paned_get_expanded (EAttachmentPaned *paned);
+void e_attachment_paned_set_expanded (EAttachmentPaned *paned,
+ gboolean expanded);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_PANED_H */
diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c
new file mode 100644
index 0000000000..2658dd06c9
--- /dev/null
+++ b/widgets/misc/e-attachment-store.c
@@ -0,0 +1,1073 @@
+/*
+ * e-attachment-store.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-store.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
+
+#include "e-file-activity.h"
+
+#define E_ATTACHMENT_STORE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStorePrivate))
+
+#define DEFAULT_ICON_NAME "mail-attachment"
+
+/* XXX Unfortunate that we have to define this here. Would
+ * prefer the attachment view classes pick their own size,
+ * but GtkIconView requires a dedicated pixbuf column. */
+#define LARGE_ICON_SIZE GTK_ICON_SIZE_DIALOG
+#define SMALL_ICON_SIZE GTK_ICON_SIZE_MENU
+
+struct _EAttachmentStorePrivate {
+ GHashTable *activity_index;
+ GHashTable *attachment_index;
+ gchar *background_filename;
+ gchar *background_options;
+ gchar *current_folder;
+
+ guint ignore_row_changed : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_BACKGROUND_FILENAME,
+ PROP_BACKGROUND_OPTIONS,
+ PROP_CURRENT_FOLDER,
+ PROP_NUM_ATTACHMENTS,
+ PROP_NUM_DOWNLOADING,
+ PROP_TOTAL_SIZE
+};
+
+enum {
+ NEW_ACTIVITY,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static const gchar *
+attachment_store_get_background_filename (EAttachmentStore *store)
+{
+ return store->priv->background_filename;
+}
+
+static void
+attachment_store_set_background_filename (EAttachmentStore *store,
+ const gchar *background_filename)
+{
+ if (background_filename == NULL)
+ background_filename = "";
+
+ g_free (store->priv->background_filename);
+ store->priv->background_filename = g_strdup (background_filename);
+
+ g_object_notify (G_OBJECT (store), "background-filename");
+}
+
+static const gchar *
+attachment_store_get_background_options (EAttachmentStore *store)
+{
+ return store->priv->background_options;
+}
+
+static void
+attachment_store_set_background_options (EAttachmentStore *store,
+ const gchar *background_options)
+{
+ if (background_options == NULL)
+ background_options = "";
+
+ g_free (store->priv->background_options);
+ store->priv->background_options = g_strdup (background_options);
+
+ g_object_notify (G_OBJECT (store), "background-options");
+}
+
+static void
+attachment_store_remove_activity (EAttachmentStore *store,
+ EActivity *activity)
+{
+ GtkTreeRowReference *reference;
+ GHashTable *hash_table;
+
+ hash_table = store->priv->activity_index;
+ reference = g_hash_table_lookup (hash_table, activity);
+
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, NULL, -1);
+ }
+
+ g_hash_table_remove (hash_table, activity);
+
+ g_object_notify (G_OBJECT (store), "num-downloading");
+}
+
+static void
+attachment_store_copy_ready (GFile *source,
+ GAsyncResult *result,
+ GtkTreeRowReference *reference)
+{
+ EAttachmentStore *store;
+ EAttachment *attachment;
+ EActivity *activity;
+ GFile *destination;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean valid;
+ GError *error = NULL;
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ valid = gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ g_return_if_fail (valid);
+
+ gtk_tree_model_get (
+ model, &iter,
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, &activity,
+ E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, &attachment, -1);
+
+ gtk_tree_row_reference_free (reference);
+
+ store = E_ATTACHMENT_STORE (model);
+
+ if (!g_file_copy_finish (source, result, &error))
+ goto fail;
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, NULL, -1);
+
+ destination = e_file_activity_get_file (E_FILE_ACTIVITY (activity));
+ e_attachment_set_file (attachment, destination);
+
+ e_activity_complete (activity);
+
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_model_row_changed (model, path, &iter);
+ gtk_tree_path_free (path);
+
+ g_object_unref (attachment);
+ g_object_unref (activity);
+
+ return;
+
+fail:
+ e_attachment_store_remove_attachment (store, attachment);
+
+ g_object_unref (attachment);
+ g_object_unref (activity);
+
+ /* XXX Do something more useful with the error. */
+ g_warning ("%s", error->message);
+ g_error_free (error);
+}
+
+static void
+attachment_store_copy_async (EAttachmentStore *store,
+ EAttachment *attachment)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GHashTable *hash_table;
+ GFile *destination;
+ GFile *source;
+ gboolean valid;
+ gchar *filename;
+ gchar *uri;
+ gint fd;
+ GError *error = NULL;
+
+ hash_table = store->priv->attachment_index;
+ reference = g_hash_table_lookup (hash_table, attachment);
+ g_return_if_fail (reference != NULL);
+
+ fd = e_file_open_tmp (&filename, &error);
+ if (error != NULL)
+ goto fail;
+
+ source = e_attachment_get_file (attachment);
+ destination = g_file_new_for_path (filename);
+
+ g_free (filename);
+ close (fd);
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ valid = gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ g_return_if_fail (valid);
+
+ uri = g_file_get_uri (source);
+ activity = e_file_activity_newv (_("Downloading '%s'"), uri);
+ g_free (uri);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, activity, -1);
+
+ reference = gtk_tree_row_reference_copy (reference);
+
+ g_hash_table_insert (hash_table, g_object_ref (activity), reference);
+
+ g_signal_connect_swapped (
+ activity, "cancelled",
+ G_CALLBACK (attachment_store_remove_activity), store);
+
+ g_signal_connect_swapped (
+ activity, "completed",
+ G_CALLBACK (attachment_store_remove_activity), store);
+
+ reference = gtk_tree_row_reference_copy (reference);
+
+ cancellable = e_file_activity_get_cancellable (
+ E_FILE_ACTIVITY (activity));
+
+ g_file_copy_async (
+ source, destination, G_FILE_COPY_OVERWRITE,
+ G_PRIORITY_DEFAULT, cancellable, (GFileProgressCallback)
+ e_file_activity_progress, activity, (GAsyncReadyCallback)
+ attachment_store_copy_ready, reference);
+
+ e_file_activity_set_file (E_FILE_ACTIVITY (activity), destination);
+ g_signal_emit (store, signals[NEW_ACTIVITY], 0, activity);
+
+ g_object_notify (G_OBJECT (store), "num-downloading");
+
+ g_object_unref (activity);
+ g_object_unref (destination);
+
+ return;
+
+fail:
+ e_attachment_store_remove_attachment (store, attachment);
+
+ /* XXX Do something more useful with the error. */
+ g_warning ("%s", error->message);
+ g_error_free (error);
+}
+
+static void
+attachment_store_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKGROUND_FILENAME:
+ attachment_store_set_background_filename (
+ E_ATTACHMENT_STORE (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_BACKGROUND_OPTIONS:
+ attachment_store_set_background_options (
+ E_ATTACHMENT_STORE (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_CURRENT_FOLDER:
+ e_attachment_store_set_current_folder (
+ E_ATTACHMENT_STORE (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_store_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKGROUND_FILENAME:
+ g_value_set_string (
+ value,
+ attachment_store_get_background_filename (
+ E_ATTACHMENT_STORE (object)));
+ return;
+
+ case PROP_BACKGROUND_OPTIONS:
+ g_value_set_string (
+ value,
+ attachment_store_get_background_options (
+ E_ATTACHMENT_STORE (object)));
+ return;
+
+ case PROP_CURRENT_FOLDER:
+ g_value_set_string (
+ value,
+ e_attachment_store_get_current_folder (
+ E_ATTACHMENT_STORE (object)));
+ return;
+
+ case PROP_NUM_ATTACHMENTS:
+ g_value_set_uint (
+ value,
+ e_attachment_store_get_num_attachments (
+ E_ATTACHMENT_STORE (object)));
+ return;
+
+ case PROP_NUM_DOWNLOADING:
+ g_value_set_uint (
+ value,
+ e_attachment_store_get_num_downloading (
+ E_ATTACHMENT_STORE (object)));
+ return;
+
+ case PROP_TOTAL_SIZE:
+ g_value_set_uint64 (
+ value,
+ e_attachment_store_get_total_size (
+ E_ATTACHMENT_STORE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_store_dispose (GObject *object)
+{
+ EAttachmentStorePrivate *priv;
+
+ priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+
+ g_hash_table_remove_all (priv->activity_index);
+ g_hash_table_remove_all (priv->attachment_index);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_store_finalize (GObject *object)
+{
+ EAttachmentStorePrivate *priv;
+
+ priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->activity_index);
+ g_hash_table_destroy (priv->attachment_index);
+
+ g_free (priv->background_filename);
+ g_free (priv->background_options);
+ g_free (priv->current_folder);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_store_constructed (GObject *object)
+{
+ EAttachmentStorePrivate *priv;
+ GConfBridge *bridge;
+ const gchar *prop;
+ const gchar *key;
+
+ priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
+ bridge = gconf_bridge_get ();
+
+ prop = "background-filename";
+ key = "/desktop/gnome/background/picture_filename";
+ gconf_bridge_bind_property (bridge, key, object, prop);
+
+ prop = "background-options";
+ key = "/desktop/gnome/background/picture_options";
+ gconf_bridge_bind_property (bridge, key, object, prop);
+}
+
+static void
+attachment_store_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter)
+{
+ EAttachmentStorePrivate *priv;
+ EAttachment *attachment;
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *large_pixbuf;
+ GdkPixbuf *small_pixbuf;
+ GIcon *icon;
+ const gchar *content_type;
+ const gchar *display_name;
+ const gchar *thumbnail_path;
+ gchar *content_description;
+ gchar *display_size;
+ gchar *icon_caption;
+ gint large_icon_size;
+ gint small_icon_size;
+ guint64 size;
+ gint column_id;
+ GError *error = NULL;
+
+ priv = E_ATTACHMENT_STORE_GET_PRIVATE (model);
+
+ if (priv->ignore_row_changed)
+ return;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ gtk_icon_size_lookup (LARGE_ICON_SIZE, &large_icon_size, NULL);
+ gtk_icon_size_lookup (SMALL_ICON_SIZE, &small_icon_size, NULL);
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ gtk_tree_model_get (model, iter, column_id, &attachment, -1);
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ content_type = e_attachment_get_content_type (attachment);
+ display_name = e_attachment_get_display_name (attachment);
+ thumbnail_path = e_attachment_get_thumbnail_path (attachment);
+ icon = e_attachment_get_icon (attachment);
+ size = e_attachment_get_size (attachment);
+
+ content_type = (content_type != NULL) ? content_type : "";
+ content_description = g_content_type_get_description (content_type);
+ display_size = g_format_size_for_display ((goffset) size);
+
+ if (size > 0)
+ icon_caption = g_strdup_printf (
+ "%s\n(%s)", display_name, display_size);
+ else
+ icon_caption = g_strdup (display_name);
+
+ /* Prefer the thumbnail if we have one. */
+ if (thumbnail_path != NULL) {
+ gint width = -1;
+ gint height = -1;
+
+ gdk_pixbuf_get_file_info (thumbnail_path, &width, &height);
+
+ large_pixbuf = gdk_pixbuf_new_from_file_at_scale (
+ thumbnail_path,
+ (width > height) ? large_icon_size : -1,
+ (width > height) ? -1 : large_icon_size,
+ TRUE, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ small_pixbuf = gdk_pixbuf_new_from_file_at_scale (
+ thumbnail_path,
+ (width > height) ? small_icon_size : -1,
+ (width > height) ? -1 : small_icon_size,
+ TRUE, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Otherwise fall back to the icon theme. */
+ } else {
+ GtkIconInfo *icon_info = NULL;
+ const gchar *filename;
+
+ if (G_IS_ICON (icon))
+ icon_info = gtk_icon_theme_lookup_by_gicon (
+ icon_theme, icon, large_icon_size, 0);
+ if (icon_info == NULL)
+ icon_info = gtk_icon_theme_lookup_icon (
+ icon_theme, DEFAULT_ICON_NAME,
+ large_icon_size, 0);
+ g_return_if_fail (icon_info != NULL);
+
+ filename = gtk_icon_info_get_filename (icon_info);
+ large_pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+ gtk_icon_info_free (icon_info);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ icon_info = NULL;
+
+ if (G_IS_ICON (icon))
+ icon_info = gtk_icon_theme_lookup_by_gicon (
+ icon_theme, icon, small_icon_size, 0);
+ if (icon_info == NULL)
+ icon_info = gtk_icon_theme_lookup_icon (
+ icon_theme, DEFAULT_ICON_NAME,
+ small_icon_size, 0);
+ g_return_if_fail (icon_info != NULL);
+
+ filename = gtk_icon_info_get_filename (icon_info);
+ small_pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+ gtk_icon_info_free (icon_info);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ /* We're about to trigger another "row-changed"
+ * signal, so this prevents infinite recursion. */
+ priv->ignore_row_changed = TRUE;
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), iter,
+ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_description,
+ E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME, display_name,
+ E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION, icon_caption,
+ E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF, large_pixbuf,
+ E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF, small_pixbuf,
+ E_ATTACHMENT_STORE_COLUMN_SIZE, size,
+ -1);
+
+ priv->ignore_row_changed = FALSE;
+
+ if (large_pixbuf != NULL)
+ g_object_unref (large_pixbuf);
+
+ if (small_pixbuf != NULL)
+ g_object_unref (small_pixbuf);
+
+ g_free (content_description);
+ g_free (display_size);
+}
+
+static void
+attachment_store_class_init (EAttachmentStoreClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentStorePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_store_set_property;
+ object_class->get_property = attachment_store_get_property;
+ object_class->dispose = attachment_store_dispose;
+ object_class->finalize = attachment_store_finalize;
+ object_class->constructed = attachment_store_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKGROUND_FILENAME,
+ g_param_spec_string (
+ "background-filename",
+ "Background Filename",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKGROUND_OPTIONS,
+ g_param_spec_string (
+ "background-options",
+ "Background Options",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURRENT_FOLDER,
+ g_param_spec_string (
+ "current-folder",
+ "Current Folder",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_NUM_ATTACHMENTS,
+ g_param_spec_uint (
+ "num-attachments",
+ "Num Attachments",
+ NULL,
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_NUM_DOWNLOADING,
+ g_param_spec_uint (
+ "num-downloading",
+ "Num Downloading",
+ NULL,
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_TOTAL_SIZE,
+ g_param_spec_uint64 (
+ "total-size",
+ "Total Size",
+ NULL,
+ 0,
+ G_MAXUINT64,
+ 0,
+ G_PARAM_READABLE));
+}
+
+static void
+attachment_store_iface_init (GtkTreeModelIface *iface)
+{
+ iface->row_changed = attachment_store_row_changed;
+}
+
+static void
+attachment_store_init (EAttachmentStore *store)
+{
+ GType types[E_ATTACHMENT_STORE_NUM_COLUMNS];
+ GHashTable *activity_index;
+ GHashTable *attachment_index;
+ gint column = 0;
+
+ activity_index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ attachment_index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ store->priv = E_ATTACHMENT_STORE_GET_PRIVATE (store);
+ store->priv->activity_index = activity_index;
+ store->priv->attachment_index = attachment_index;
+
+ types[column++] = E_TYPE_ACTIVITY; /* COLUMN_ACTIVITY */
+ types[column++] = E_TYPE_ATTACHMENT; /* COLUMN_ATTACHMENT */
+ types[column++] = G_TYPE_STRING; /* COLUMN_CONTENT_TYPE */
+ types[column++] = G_TYPE_STRING; /* COLUMN_DISPLAY_NAME */
+ types[column++] = G_TYPE_STRING; /* COLUMN_ICON_CAPTION */
+ types[column++] = GDK_TYPE_PIXBUF; /* COLUMN_LARGE_PIXBUF */
+ types[column++] = GDK_TYPE_PIXBUF; /* COLUMN_SMALL_PIXBUF */
+ types[column++] = G_TYPE_UINT64; /* COLUMN_SIZE */
+
+ g_assert (column == E_ATTACHMENT_STORE_NUM_COLUMNS);
+
+ gtk_list_store_set_column_types (
+ GTK_LIST_STORE (store), G_N_ELEMENTS (types), types);
+}
+
+GType
+e_attachment_store_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentStoreClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_store_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAttachmentStore),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_store_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) attachment_store_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_LIST_STORE, "EAttachmentStore",
+ &type_info, 0);
+
+ g_type_add_interface_static (
+ type, GTK_TYPE_TREE_MODEL, &iface_info);
+ }
+
+ return type;
+}
+
+GtkTreeModel *
+e_attachment_store_new (void)
+{
+ return g_object_new (E_TYPE_ATTACHMENT_STORE, NULL);
+}
+
+void
+e_attachment_store_add_attachment (EAttachmentStore *store,
+ EAttachment *attachment)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GFile *file;
+
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, attachment, -1);
+
+ model = GTK_TREE_MODEL (store);
+ path = gtk_tree_model_get_path (model, &iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ g_hash_table_insert (
+ store->priv->attachment_index,
+ g_object_ref (attachment), reference);
+
+ file = e_attachment_get_file (attachment);
+
+ /* This lets the attachment tell us when to update. */
+ _e_attachment_set_reference (attachment, reference);
+
+ if (!g_file_is_native (file))
+ attachment_store_copy_async (store, attachment);
+
+ g_object_freeze_notify (G_OBJECT (store));
+ g_object_notify (G_OBJECT (store), "num-attachments");
+ g_object_notify (G_OBJECT (store), "total-size");
+ g_object_thaw_notify (G_OBJECT (store));
+}
+
+gboolean
+e_attachment_store_remove_attachment (EAttachmentStore *store,
+ EAttachment *attachment)
+{
+ GtkTreeRowReference *reference;
+ GHashTable *hash_table;
+ EActivity *activity;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), FALSE);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ hash_table = store->priv->attachment_index;
+ reference = g_hash_table_lookup (hash_table, attachment);
+
+ if (reference == NULL)
+ return FALSE;
+
+ if (!gtk_tree_row_reference_valid (reference)) {
+ g_hash_table_remove (hash_table, attachment);
+ return FALSE;
+ }
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (
+ model, &iter,
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, &activity, -1);
+
+ if (activity != NULL) {
+ /* Cancel the file transfer. */
+ e_activity_cancel (activity);
+ g_object_unref (activity);
+ }
+
+ gtk_list_store_remove (GTK_LIST_STORE (store), &iter);
+ g_hash_table_remove (hash_table, attachment);
+
+ g_object_freeze_notify (G_OBJECT (store));
+ g_object_notify (G_OBJECT (store), "num-attachments");
+ g_object_notify (G_OBJECT (store), "total-size");
+ g_object_thaw_notify (G_OBJECT (store));
+
+ return TRUE;
+}
+
+void
+e_attachment_store_add_to_multipart (EAttachmentStore *store,
+ CamelMultipart *multipart,
+ const gchar *default_charset)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (CAMEL_MULTIPART (multipart));
+
+ model = GTK_TREE_MODEL (store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ EAttachment *attachment;
+ gint column_id;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+
+ e_attachment_add_to_multipart (
+ attachment, multipart, default_charset);
+
+ g_object_unref (attachment);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+}
+
+const gchar *
+e_attachment_store_get_current_folder (EAttachmentStore *store)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL);
+
+ return store->priv->current_folder;
+}
+
+void
+e_attachment_store_set_current_folder (EAttachmentStore *store,
+ const gchar *current_folder)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ if (current_folder == NULL)
+ current_folder = g_get_home_dir ();
+
+ g_free (store->priv->current_folder);
+ store->priv->current_folder = g_strdup (current_folder);
+
+ g_object_notify (G_OBJECT (store), "current-folder");
+}
+
+guint
+e_attachment_store_get_num_attachments (EAttachmentStore *store)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+ return g_hash_table_size (store->priv->attachment_index);
+}
+
+guint
+e_attachment_store_get_num_downloading (EAttachmentStore *store)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+ return g_hash_table_size (store->priv->activity_index);
+}
+
+guint64
+e_attachment_store_get_total_size (EAttachmentStore *store)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ guint64 total_size = 0;
+ gboolean valid;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0);
+
+ model = GTK_TREE_MODEL (store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ EAttachment *attachment;
+ gint column_id;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+ total_size += e_attachment_get_size (attachment);
+ g_object_unref (attachment);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ return total_size;
+}
+
+gint
+e_attachment_store_run_file_chooser_dialog (EAttachmentStore *store,
+ GtkWidget *dialog)
+{
+ GtkFileChooser *file_chooser;
+ gint response = GTK_RESPONSE_NONE;
+ const gchar *current_folder;
+ gboolean update_folder;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), response);
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ current_folder = e_attachment_store_get_current_folder (store);
+ gtk_file_chooser_set_current_folder (file_chooser, current_folder);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ update_folder =
+ (response == GTK_RESPONSE_ACCEPT) ||
+ (response == GTK_RESPONSE_OK) ||
+ (response == GTK_RESPONSE_YES) ||
+ (response == GTK_RESPONSE_APPLY);
+
+ if (update_folder) {
+ gchar *folder;
+
+ folder = gtk_file_chooser_get_current_folder (file_chooser);
+ e_attachment_store_set_current_folder (store, folder);
+ g_free (folder);
+ }
+
+ return response;
+}
+
+void
+e_attachment_store_run_load_dialog (EAttachmentStore *store,
+ GtkWindow *parent)
+{
+ GtkFileChooser *file_chooser;
+ GtkWidget *dialog;
+ GtkWidget *option;
+ GSList *files, *iter;
+ const gchar *disposition;
+ gboolean active;
+ gint response;
+
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Add Attachment"), parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("A_ttach"), GTK_RESPONSE_OK, NULL);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ gtk_file_chooser_set_local_only (file_chooser, FALSE);
+ gtk_file_chooser_set_select_multiple (file_chooser, TRUE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment");
+
+ option = gtk_check_button_new_with_mnemonic (
+ _("_Suggest automatic display of attachment"));
+ gtk_file_chooser_set_extra_widget (file_chooser, option);
+ gtk_widget_show (option);
+
+ response = e_attachment_store_run_file_chooser_dialog (store, dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ files = gtk_file_chooser_get_files (file_chooser);
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
+ disposition = active ? "inline" : "attachment";
+
+ for (iter = files; iter != NULL; iter = g_slist_next (iter)) {
+ EAttachment *attachment;
+ GFile *file = iter->data;
+
+ attachment = e_attachment_new ();
+ e_attachment_set_file (attachment, file);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+ }
+
+ g_slist_foreach (files, (GFunc) g_object_unref, NULL);
+ g_slist_free (files);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
+
+void
+e_attachment_store_run_save_dialog (EAttachmentStore *store,
+ EAttachment *attachment,
+ GtkWindow *parent)
+{
+ GtkFileChooser *file_chooser;
+ GtkWidget *dialog;
+ GFile *file;
+ EActivity *activity;
+ const gchar *display_name;
+ gint response;
+
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Save Attachment"), parent,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ gtk_file_chooser_set_local_only (file_chooser, FALSE);
+ gtk_file_chooser_set_do_overwrite_confirmation (file_chooser, TRUE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment");
+
+ display_name = e_attachment_get_display_name (attachment);
+ if (display_name != NULL)
+ gtk_file_chooser_set_current_name (file_chooser, display_name);
+
+ response = e_attachment_store_run_file_chooser_dialog (store, dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ file = gtk_file_chooser_get_file (file_chooser);
+ activity = e_file_activity_new (_("Saving attachment"));
+ e_attachment_save_async (
+ attachment, E_FILE_ACTIVITY (activity), file);
+ g_signal_emit (store, signals[NEW_ACTIVITY], 0, activity);
+ g_object_unref (activity);
+ g_object_unref (file);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
diff --git a/widgets/misc/e-attachment-store.h b/widgets/misc/e-attachment-store.h
new file mode 100644
index 0000000000..906aee6638
--- /dev/null
+++ b/widgets/misc/e-attachment-store.h
@@ -0,0 +1,110 @@
+/*
+ * e-attachment-store.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_STORE_H
+#define E_ATTACHMENT_STORE_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_STORE \
+ (e_attachment_store_get_type ())
+#define E_ATTACHMENT_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStore))
+#define E_ATTACHMENT_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_STORE, EAttachmentStoreClass))
+#define E_IS_ATTACHMENT_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_STORE))
+#define E_IS_ATTACHMENT_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_STORE))
+#define E_ATTACHMENT_STORE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_STORE, EAttachmentStoreClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentStore EAttachmentStore;
+typedef struct _EAttachmentStoreClass EAttachmentStoreClass;
+typedef struct _EAttachmentStorePrivate EAttachmentStorePrivate;
+
+struct _EAttachmentStore {
+ GtkListStore parent;
+ EAttachmentStorePrivate *priv;
+};
+
+struct _EAttachmentStoreClass {
+ GtkListStoreClass parent_class;
+};
+
+enum {
+ E_ATTACHMENT_STORE_COLUMN_ACTIVITY, /* E_TYPE_ACTIVITY */
+ E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, /* E_TYPE_ATTACHMENT */
+ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, /* G_TYPE_STRING */
+ E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME, /* G_TYPE_STRING */
+ E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION, /* G_TYPE_STRING */
+ E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF, /* GDK_TYPE_PIXBUF */
+ E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF, /* GDK_TYPE_PIXBUF */
+ E_ATTACHMENT_STORE_COLUMN_SIZE, /* G_TYPE_UINT64 */
+ E_ATTACHMENT_STORE_NUM_COLUMNS
+};
+
+GType e_attachment_store_get_type (void);
+GtkTreeModel * e_attachment_store_new (void);
+void e_attachment_store_add_attachment
+ (EAttachmentStore *store,
+ EAttachment *attachment);
+gboolean e_attachment_store_remove_attachment
+ (EAttachmentStore *store,
+ EAttachment *attachment);
+void e_attachment_store_add_to_multipart
+ (EAttachmentStore *store,
+ CamelMultipart *multipart,
+ const gchar *default_charset);
+const gchar * e_attachment_store_get_current_folder
+ (EAttachmentStore *store);
+void e_attachment_store_set_current_folder
+ (EAttachmentStore *store,
+ const gchar *current_folder);
+guint e_attachment_store_get_num_attachments
+ (EAttachmentStore *store);
+guint e_attachment_store_get_num_downloading
+ (EAttachmentStore *store);
+guint64 e_attachment_store_get_total_size
+ (EAttachmentStore *store);
+gint e_attachment_store_run_file_chooser_dialog
+ (EAttachmentStore *store,
+ GtkWidget *dialog);
+void e_attachment_store_run_load_dialog
+ (EAttachmentStore *store,
+ GtkWindow *parent);
+void e_attachment_store_run_save_dialog
+ (EAttachmentStore *store,
+ EAttachment *attachment,
+ GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_STORE_H */
diff --git a/widgets/misc/e-attachment-tree-view.c b/widgets/misc/e-attachment-tree-view.c
new file mode 100644
index 0000000000..817a6c7dab
--- /dev/null
+++ b/widgets/misc/e-attachment-tree-view.c
@@ -0,0 +1,396 @@
+/*
+ * e-attachment-tree-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-tree-view.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "e-attachment.h"
+#include "e-attachment-store.h"
+#include "e-attachment-view.h"
+
+#define E_ATTACHMENT_TREE_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewPrivate))
+
+struct _EAttachmentTreeViewPrivate {
+ EAttachmentViewPrivate view_priv;
+};
+
+static gpointer parent_class;
+
+static void
+attachment_tree_view_dispose (GObject *object)
+{
+ e_attachment_view_dispose (E_ATTACHMENT_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_tree_view_finalize (GObject *object)
+{
+ e_attachment_view_finalize (E_ATTACHMENT_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_tree_view_render_size (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ gchar *display_size;
+ gint column_id;
+ guint64 size;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_SIZE;
+ gtk_tree_model_get (model, iter, column_id, &size, -1);
+
+ display_size = g_format_size_for_display ((goffset) size);
+ g_object_set (renderer, "text", display_size, NULL);
+ g_free (display_size);
+}
+
+static gboolean
+attachment_tree_view_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+ e_attachment_view_show_popup_menu (view, event);
+ return TRUE;
+ }
+
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_press_event (widget, event);
+}
+
+static gboolean
+attachment_tree_view_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ if (event->keyval == GDK_Delete) {
+ e_attachment_view_remove_selected (view, TRUE);
+ return TRUE;
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ key_press_event (widget, event);
+}
+
+static gboolean
+attachment_tree_view_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+attachment_tree_view_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ e_attachment_view_drag_data_received (
+ view, context, x, y, selection, info, time);
+}
+
+static gboolean
+attachment_tree_view_popup_menu (GtkWidget *widget)
+{
+ EAttachmentView *view = E_ATTACHMENT_VIEW (widget);
+
+ e_attachment_view_show_popup_menu (view, NULL);
+
+ return TRUE;
+}
+
+static EAttachmentViewPrivate *
+attachment_tree_view_get_private (EAttachmentView *view)
+{
+ EAttachmentTreeViewPrivate *priv;
+
+ priv = E_ATTACHMENT_TREE_VIEW_GET_PRIVATE (view);
+
+ return &priv->view_priv;
+}
+
+static EAttachmentStore *
+attachment_tree_view_get_store (EAttachmentView *view)
+{
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+
+ tree_view = GTK_TREE_VIEW (view);
+ model = gtk_tree_view_get_model (tree_view);
+
+ return E_ATTACHMENT_STORE (model);
+}
+
+static GtkTreePath *
+attachment_tree_view_get_path_at_pos (EAttachmentView *view,
+ gint x,
+ gint y)
+{
+ GtkTreeView *tree_view;
+ GtkTreePath *path;
+ gboolean row_exists;
+
+ tree_view = GTK_TREE_VIEW (view);
+
+ row_exists = gtk_tree_view_get_path_at_pos (
+ tree_view, x, y, &path, NULL, NULL, NULL);
+
+ return row_exists ? path : NULL;
+}
+
+static GList *
+attachment_tree_view_get_selected_paths (EAttachmentView *view)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ return gtk_tree_selection_get_selected_rows (selection, NULL);
+}
+
+static gboolean
+attachment_tree_view_path_is_selected (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ return gtk_tree_selection_path_is_selected (selection, path);
+}
+
+static void
+attachment_tree_view_select_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ gtk_tree_selection_select_path (selection, path);
+}
+
+static void
+attachment_tree_view_unselect_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ gtk_tree_selection_unselect_path (selection, path);
+}
+
+static void
+attachment_tree_view_select_all (EAttachmentView *view)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ gtk_tree_selection_select_all (selection);
+}
+
+static void
+attachment_tree_view_unselect_all (EAttachmentView *view)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ gtk_tree_selection_unselect_all (selection);
+}
+
+static void
+attachment_tree_view_class_init (EAttachmentTreeViewClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = attachment_tree_view_dispose;
+ object_class->finalize = attachment_tree_view_finalize;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->button_press_event = attachment_tree_view_button_press_event;
+ widget_class->key_press_event = attachment_tree_view_key_press_event;
+ widget_class->drag_motion = attachment_tree_view_drag_motion;
+ widget_class->drag_data_received = attachment_tree_view_drag_data_received;
+ widget_class->popup_menu = attachment_tree_view_popup_menu;
+}
+
+static void
+attachment_tree_view_iface_init (EAttachmentViewIface *iface)
+{
+ iface->get_private = attachment_tree_view_get_private;
+ iface->get_store = attachment_tree_view_get_store;
+
+ iface->get_path_at_pos = attachment_tree_view_get_path_at_pos;
+ iface->get_selected_paths = attachment_tree_view_get_selected_paths;
+ iface->path_is_selected = attachment_tree_view_path_is_selected;
+ iface->select_path = attachment_tree_view_select_path;
+ iface->unselect_path = attachment_tree_view_unselect_path;
+ iface->select_all = attachment_tree_view_select_all;
+ iface->unselect_all = attachment_tree_view_unselect_all;
+}
+
+static void
+attachment_tree_view_init (EAttachmentTreeView *tree_view)
+{
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ tree_view->priv = E_ATTACHMENT_TREE_VIEW_GET_PRIVATE (tree_view);
+
+ e_attachment_view_init (E_ATTACHMENT_VIEW (tree_view));
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_column_set_spacing (column, 3);
+ gtk_tree_view_column_set_title (column, _("Name"));
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "pixbuf",
+ E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "text",
+ E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Size"));
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ gtk_tree_view_column_set_cell_data_func (
+ column, renderer, (GtkTreeCellDataFunc)
+ attachment_tree_view_render_size, NULL, NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Type"));
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "text",
+ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE);
+}
+
+GType
+e_attachment_tree_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentTreeViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_tree_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAttachmentTreeView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_tree_view_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) attachment_tree_view_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TREE_VIEW, "EAttachmentTreeView",
+ &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_ATTACHMENT_VIEW, &iface_info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_attachment_tree_view_new (void)
+{
+ return g_object_new (E_TYPE_ATTACHMENT_TREE_VIEW, NULL);
+}
diff --git a/widgets/misc/e-attachment-tree-view.h b/widgets/misc/e-attachment-tree-view.h
new file mode 100644
index 0000000000..7f16ba5ab2
--- /dev/null
+++ b/widgets/misc/e-attachment-tree-view.h
@@ -0,0 +1,66 @@
+/*
+ * e-attachment-tree-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_TREE_VIEW_H
+#define E_ATTACHMENT_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_TREE_VIEW \
+ (e_attachment_tree_view_get_type ())
+#define E_ATTACHMENT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeView))
+#define E_ATTACHMENT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewClass))
+#define E_IS_ATTACHMENT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_TREE_VIEW))
+#define E_IS_ATTACHMENT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_TREE_VIEW))
+#define E_ATTACHMENT_TREE_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_TREE_VIEW, EAttachmentTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentTreeView EAttachmentTreeView;
+typedef struct _EAttachmentTreeViewClass EAttachmentTreeViewClass;
+typedef struct _EAttachmentTreeViewPrivate EAttachmentTreeViewPrivate;
+
+struct _EAttachmentTreeView {
+ GtkTreeView parent;
+ EAttachmentTreeViewPrivate *priv;
+};
+
+struct _EAttachmentTreeViewClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType e_attachment_tree_view_get_type (void);
+GtkWidget * e_attachment_tree_view_new (void);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_TREE_VIEW_H */
diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c
new file mode 100644
index 0000000000..198ce75d31
--- /dev/null
+++ b/widgets/misc/e-attachment-view.c
@@ -0,0 +1,1041 @@
+/*
+ * e-attachment-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-view.h"
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <camel/camel-stream-mem.h>
+
+#include "e-util/e-plugin-ui.h"
+#include "e-util/e-util.h"
+#include "e-attachment-dialog.h"
+
+enum {
+ DND_TYPE_MESSAGE_RFC822,
+ DND_TYPE_X_UID_LIST,
+ DND_TYPE_TEXT_URI_LIST,
+ DND_TYPE_NETSCAPE_URL,
+ DND_TYPE_TEXT_VCARD,
+ DND_TYPE_TEXT_CALENDAR
+};
+
+static GtkTargetEntry drop_types[] = {
+ { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 },
+ { "x-uid-list", 0, DND_TYPE_X_UID_LIST },
+ { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST },
+ { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL },
+ { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD },
+ { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR }
+};
+
+/* The atoms need initialized at runtime. */
+static struct {
+ const gchar *target;
+ GdkAtom atom;
+ GdkDragAction actions;
+} drag_info[] = {
+ { "message/rfc822", NULL, GDK_ACTION_COPY },
+ { "x-uid-list", NULL, GDK_ACTION_COPY |
+ GDK_ACTION_MOVE |
+ GDK_ACTION_ASK },
+ { "text/uri-list", NULL, GDK_ACTION_COPY },
+ { "_NETSCAPE_URL", NULL, GDK_ACTION_COPY },
+ { "text/x-vcard", NULL, GDK_ACTION_COPY },
+ { "text/calendar", NULL, GDK_ACTION_COPY }
+};
+
+static const gchar *ui =
+"<ui>"
+" <popup name='context'>"
+" <menuitem action='save-as'/>"
+" <menuitem action='set-background'/>"
+" <menuitem action='remove'/>"
+" <menuitem action='properties'/>"
+" <placeholder name='custom-actions'/>"
+" <separator/>"
+" <menuitem action='add'/>"
+" <separator/>"
+" <placeholder name='open-actions'/>"
+" </popup>"
+" <popup name='dnd'>"
+" <menuitem action='drag-copy'/>"
+" <menuitem action='drag-move'/>"
+" <separator/>"
+" <menuitem action='drag-cancel'/>"
+" </popup>"
+"</ui>";
+
+static void
+action_add_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachmentStore *store;
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ store = e_attachment_view_get_store (view);
+ e_attachment_store_run_load_dialog (store, parent);
+}
+
+static void
+action_drag_cancel_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+
+ priv = e_attachment_view_get_private (view);
+ gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+static void
+action_drag_copy_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ e_attachment_view_drag_action (view, GDK_ACTION_COPY);
+}
+
+static void
+action_drag_move_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ e_attachment_view_drag_action (view, GDK_ACTION_MOVE);
+}
+
+static void
+action_properties_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachment *attachment;
+ GtkWidget *dialog;
+ GList *selected;
+ gpointer parent;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+ attachment = selected->data;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ dialog = e_attachment_dialog_new (parent, attachment);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
+action_recent_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ GtkRecentChooser *chooser;
+ EAttachmentStore *store;
+ EAttachment *attachment;
+ gchar *uri;
+
+ chooser = GTK_RECENT_CHOOSER (action);
+ store = e_attachment_view_get_store (view);
+
+ uri = gtk_recent_chooser_get_current_uri (chooser);
+ attachment = e_attachment_new_for_uri (uri);
+ e_attachment_store_add_attachment (store, attachment);
+ g_free (uri);
+}
+
+static void
+action_remove_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ e_attachment_view_remove_selected (view, FALSE);
+}
+
+static void
+action_save_as_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+}
+
+static void
+action_set_background_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+}
+
+static GtkActionEntry standard_entries[] = {
+
+ { "drag-cancel",
+ NULL,
+ N_("Cancel _Drag"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_drag_cancel_cb) },
+
+ { "drag-copy",
+ NULL,
+ N_("_Copy"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_drag_copy_cb) },
+
+ { "drag-move",
+ NULL,
+ N_("_Move"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_drag_move_cb) },
+
+ { "save-as",
+ GTK_STOCK_SAVE_AS,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_save_as_cb) },
+
+ { "set-background",
+ NULL,
+ N_("Set as _Background"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_set_background_cb) }
+};
+
+static GtkActionEntry editable_entries[] = {
+
+ { "add",
+ GTK_STOCK_ADD,
+ N_("A_dd Attachment..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_add_cb) },
+
+ { "properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_properties_cb) },
+
+ { "remove",
+ GTK_STOCK_REMOVE,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_remove_cb) }
+};
+
+static void
+drop_message_rfc822 (EAttachmentView *view,
+ GtkSelectionData *selection_data,
+ EAttachmentStore *store,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+ EAttachment *attachment;
+ CamelMimeMessage *message;
+ CamelDataWrapper *wrapper;
+ CamelStream *stream;
+ const gchar *data;
+ gboolean success = FALSE;
+ gboolean delete = FALSE;
+ gint length;
+
+ priv = e_attachment_view_get_private (view);
+
+ data = (const gchar *) gtk_selection_data_get_data (selection_data);
+ length = gtk_selection_data_get_length (selection_data);
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write (stream, data, length);
+ camel_stream_reset (stream);
+
+ message = camel_mime_message_new ();
+ wrapper = CAMEL_DATA_WRAPPER (message);
+
+ if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1)
+ goto exit;
+
+ attachment = e_attachment_new_for_message (message);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+
+ success = TRUE;
+ delete = (action == GDK_ACTION_MOVE);
+
+exit:
+ camel_object_unref (message);
+ camel_object_unref (stream);
+
+ gtk_drag_finish (priv->drag_context, success, delete, priv->time);
+}
+
+static void
+drop_netscape_url (EAttachmentView *view,
+ GtkSelectionData *selection_data,
+ EAttachmentStore *store,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+ EAttachment *attachment;
+ const gchar *data;
+ gchar *copied_data;
+ gchar **strv;
+ gint length;
+
+ /* _NETSCAPE_URL is represented as "URI\nTITLE" */
+
+ priv = e_attachment_view_get_private (view);
+
+ data = (const gchar *) gtk_selection_data_get_data (selection_data);
+ length = gtk_selection_data_get_length (selection_data);
+
+ copied_data = g_strndup (data, length);
+ strv = g_strsplit (copied_data, "\n", 2);
+ g_free (copied_data);
+
+ attachment = e_attachment_new_for_uri (strv[0]);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+
+ g_strfreev (strv);
+
+ gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_text_uri_list (EAttachmentView *view,
+ GtkSelectionData *selection_data,
+ EAttachmentStore *store,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+ gchar **uris;
+ gint ii;
+
+ priv = e_attachment_view_get_private (view);
+
+ uris = gtk_selection_data_get_uris (selection_data);
+
+ for (ii = 0; uris[ii] != NULL; ii++) {
+ EAttachment *attachment;
+
+ attachment = e_attachment_new_for_uri (uris[ii]);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+ }
+
+ g_strfreev (uris);
+
+ gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_text_generic (EAttachmentView *view,
+ GtkSelectionData *selection_data,
+ EAttachmentStore *store,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ GdkAtom atom;
+ const gchar *data;
+ gchar *content_type;
+ gint length;
+
+ priv = e_attachment_view_get_private (view);
+
+ data = (const gchar *) gtk_selection_data_get_data (selection_data);
+ length = gtk_selection_data_get_length (selection_data);
+ atom = gtk_selection_data_get_data_type (selection_data);
+
+ mime_part = camel_mime_part_new ();
+
+ content_type = gdk_atom_name (atom);
+ camel_mime_part_set_content (mime_part, data, length, content_type);
+ camel_mime_part_set_disposition (mime_part, "inline");
+ g_free (content_type);
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ e_attachment_store_add_attachment (store, attachment);
+ g_object_unref (attachment);
+
+ camel_object_unref (mime_part);
+
+ gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+}
+
+static void
+drop_x_uid_list (EAttachmentView *view,
+ GtkSelectionData *selection_data,
+ EAttachmentStore *store,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+
+ /* FIXME Ugh, this looks painful. Requires mailer stuff. */
+
+ priv = e_attachment_view_get_private (view);
+
+ gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+static void
+attachment_view_class_init (EAttachmentViewIface *iface)
+{
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) {
+ const gchar *target = drag_info[ii].target;
+ drag_info[ii].atom = gdk_atom_intern (target, FALSE);
+ }
+}
+
+GType
+e_attachment_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentViewIface),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_INTERFACE, "EAttachmentView", &type_info, 0);
+
+ g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET);
+ }
+
+ return type;
+}
+
+void
+e_attachment_view_init (EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ const gchar *domain = GETTEXT_PACKAGE;
+ GError *error = NULL;
+
+ priv = e_attachment_view_get_private (view);
+
+ gtk_drag_dest_set (
+ GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL,
+ drop_types, G_N_ELEMENTS (drop_types),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+
+ ui_manager = gtk_ui_manager_new ();
+ priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+ priv->ui_manager = ui_manager;
+
+ action_group = gtk_action_group_new ("standard");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, standard_entries,
+ G_N_ELEMENTS (standard_entries), view);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ priv->standard_actions = action_group;
+
+ action_group = gtk_action_group_new ("editable");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, editable_entries,
+ G_N_ELEMENTS (editable_entries), view);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ priv->editable_actions = action_group;
+
+ action_group = gtk_action_group_new ("openwith");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ priv->openwith_actions = action_group;
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here implies a malformed
+ * UI definition. Full stop. */
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+ if (error != NULL)
+ g_error ("%s", error->message);
+
+ e_plugin_ui_register_manager (ui_manager, "attachment-view", view);
+}
+
+void
+e_attachment_view_dispose (EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+
+ priv = e_attachment_view_get_private (view);
+
+ if (priv->ui_manager != NULL) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ if (priv->standard_actions != NULL) {
+ g_object_unref (priv->standard_actions);
+ priv->standard_actions = NULL;
+ }
+
+ if (priv->editable_actions != NULL) {
+ g_object_unref (priv->editable_actions);
+ priv->editable_actions = NULL;
+ }
+
+ if (priv->openwith_actions != NULL) {
+ g_object_unref (priv->openwith_actions);
+ priv->openwith_actions = NULL;
+ }
+
+ if (priv->drag_context != NULL) {
+ g_object_unref (priv->drag_context);
+ priv->drag_context = NULL;
+ }
+}
+
+void
+e_attachment_view_finalize (EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+
+ priv = e_attachment_view_get_private (view);
+
+ if (priv->selection_data != NULL)
+ gtk_selection_data_free (priv->selection_data);
+}
+
+EAttachmentViewPrivate *
+e_attachment_view_get_private (EAttachmentView *view)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_val_if_fail (iface->get_private != NULL, NULL);
+
+ return iface->get_private (view);
+}
+
+EAttachmentStore *
+e_attachment_view_get_store (EAttachmentView *view)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_val_if_fail (iface->get_store != NULL, NULL);
+
+ return iface->get_store (view);
+}
+
+GList *
+e_attachment_view_get_selected_attachments (EAttachmentView *view)
+{
+ EAttachmentStore *store;
+ GtkTreeModel *model;
+ GList *selected, *item;
+ gint column_id;
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ selected = e_attachment_view_get_selected_paths (view);
+ store = e_attachment_view_get_store (view);
+ model = GTK_TREE_MODEL (store);
+
+ /* Convert the GtkTreePaths to EAttachments. */
+ for (item = selected; item != NULL; item = item->next) {
+ EAttachment *attachment;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = item->data;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+ gtk_tree_path_free (path);
+
+ item->data = attachment;
+ }
+
+ return selected;
+}
+void
+e_attachment_view_remove_selected (EAttachmentView *view,
+ gboolean select_next)
+{
+ EAttachmentStore *store;
+ GtkTreeModel *model;
+ GList *selected, *item;
+ gint column_id;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+ selected = e_attachment_view_get_selected_paths (view);
+ store = e_attachment_view_get_store (view);
+ model = GTK_TREE_MODEL (store);
+
+ for (item = selected; item != NULL; item = item->next) {
+ EAttachment *attachment;
+ GtkTreePath *path = item->data;
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+ e_attachment_store_remove_attachment (store, attachment);
+ g_object_unref (attachment);
+ }
+
+ /* If we only removed one attachment, try to select another. */
+ if (select_next && g_list_length (selected) == 1) {
+ GtkTreePath *path = selected->data;
+
+ e_attachment_view_select_path (view, path);
+ if (!e_attachment_view_path_is_selected (view, path))
+ if (gtk_tree_path_prev (path))
+ e_attachment_view_select_path (view, path);
+ }
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+}
+
+GtkTreePath *
+e_attachment_view_get_path_at_pos (EAttachmentView *view,
+ gint x,
+ gint y)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_val_if_fail (iface->get_path_at_pos != NULL, NULL);
+
+ return iface->get_path_at_pos (view, x, y);
+}
+
+GList *
+e_attachment_view_get_selected_paths (EAttachmentView *view)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_val_if_fail (iface->get_selected_paths != NULL, NULL);
+
+ return iface->get_selected_paths (view);
+}
+
+gboolean
+e_attachment_view_path_is_selected (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_val_if_fail (iface->path_is_selected != NULL, FALSE);
+
+ return iface->path_is_selected (view, path);
+}
+
+void
+e_attachment_view_select_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+ g_return_if_fail (path != NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_if_fail (iface->select_path != NULL);
+
+ iface->select_path (view, path);
+}
+
+void
+e_attachment_view_unselect_path (EAttachmentView *view,
+ GtkTreePath *path)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+ g_return_if_fail (path != NULL);
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_if_fail (iface->unselect_path != NULL);
+
+ iface->unselect_path (view, path);
+}
+
+void
+e_attachment_view_select_all (EAttachmentView *view)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_if_fail (iface->select_all != NULL);
+
+ iface->select_all (view);
+}
+
+void
+e_attachment_view_unselect_all (EAttachmentView *view)
+{
+ EAttachmentViewIface *iface;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ iface = E_ATTACHMENT_VIEW_GET_IFACE (view);
+ g_return_if_fail (iface->unselect_all != NULL);
+
+ iface->unselect_all (view);
+}
+
+void
+e_attachment_view_sync_selection (EAttachmentView *view,
+ EAttachmentView *target)
+{
+ GList *selected, *iter;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (target));
+
+ selected = e_attachment_view_get_selected_paths (view);
+ e_attachment_view_unselect_all (target);
+
+ for (iter = selected; iter != NULL; iter = iter->next)
+ e_attachment_view_select_path (target, iter->data);
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+}
+
+void
+e_attachment_view_drag_action (EAttachmentView *view,
+ GdkDragAction action)
+{
+ EAttachmentViewPrivate *priv;
+ GtkSelectionData *selection_data;
+ EAttachmentStore *store;
+ GdkAtom atom;
+ gchar *name;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ priv = e_attachment_view_get_private (view);
+
+ selection_data = priv->selection_data;
+ store = e_attachment_view_get_store (view);
+ atom = gtk_selection_data_get_data_type (selection_data);
+
+ switch (priv->info) {
+ case DND_TYPE_MESSAGE_RFC822:
+ drop_message_rfc822 (
+ view, selection_data, store, action);
+ return;
+
+ case DND_TYPE_NETSCAPE_URL:
+ drop_netscape_url (
+ view, selection_data, store, action);
+ return;
+
+ case DND_TYPE_TEXT_URI_LIST:
+ drop_text_uri_list (
+ view, selection_data, store, action);
+ return;
+
+ case DND_TYPE_TEXT_VCARD:
+ case DND_TYPE_TEXT_CALENDAR:
+ drop_text_generic (
+ view, selection_data, store, action);
+ return;
+
+ case DND_TYPE_X_UID_LIST:
+ drop_x_uid_list (
+ view, selection_data, store, action);
+ return;
+
+ default:
+ name = gdk_atom_name (atom);
+ g_warning ("Unknown drag type: %s", name);
+ g_free (name);
+ break;
+ }
+
+ gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+}
+
+gboolean
+e_attachment_view_drag_motion (EAttachmentView *view,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GList *iter;
+ GdkDragAction actions = 0;
+ GdkDragAction chosen_action;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
+
+ for (iter = context->targets; iter != NULL; iter = iter->next) {
+ GdkAtom atom = iter->data;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
+ if (atom == drag_info[ii].atom)
+ actions |= drag_info[ii].actions;
+ }
+
+ actions &= context->actions;
+ chosen_action = context->suggested_action;
+
+ if (chosen_action == GDK_ACTION_ASK) {
+ GdkDragAction mask;
+
+ mask = GDK_ACTION_COPY | GDK_ACTION_MOVE;
+ if ((actions & mask) != mask)
+ chosen_action = GDK_ACTION_COPY;
+ }
+
+ gdk_drag_status (context, chosen_action, time);
+
+ return (chosen_action != 0);
+}
+
+void
+e_attachment_view_drag_data_received (EAttachmentView *view,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ EAttachmentViewPrivate *priv;
+ GtkUIManager *ui_manager;
+ GdkDragAction action;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ priv = e_attachment_view_get_private (view);
+ ui_manager = e_attachment_view_get_ui_manager (view);
+
+ action = drag_context->action;
+
+ if (gtk_selection_data_get_data (selection_data) == NULL)
+ return;
+
+ if (gtk_selection_data_get_length (selection_data) == -1)
+ return;
+
+ if (priv->drag_context != NULL)
+ g_object_unref (priv->drag_context);
+
+ if (priv->selection_data != NULL)
+ gtk_selection_data_free (priv->selection_data);
+
+ priv->drag_context = g_object_ref (drag_context);
+ priv->selection_data = gtk_selection_data_copy (selection_data);
+ priv->info = info;
+ priv->time = time;
+
+ if (action == GDK_ACTION_ASK) {
+ GtkWidget *menu;
+
+ menu = gtk_ui_manager_get_widget (ui_manager, "/dnd");
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, time);
+ } else
+ e_attachment_view_drag_action (view, action);
+}
+
+GtkAction *
+e_attachment_view_get_action (EAttachmentView *view,
+ const gchar *action_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ ui_manager = e_attachment_view_get_ui_manager (view);
+
+ return e_lookup_action (ui_manager, action_name);
+}
+
+GtkActionGroup *
+e_attachment_view_get_action_group (EAttachmentView *view,
+ const gchar *group_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+ g_return_val_if_fail (group_name != NULL, NULL);
+
+ ui_manager = e_attachment_view_get_ui_manager (view);
+
+ return e_lookup_action_group (ui_manager, group_name);
+}
+
+GtkUIManager *
+e_attachment_view_get_ui_manager (EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+ priv = e_attachment_view_get_private (view);
+
+ return priv->ui_manager;
+}
+
+GtkAction *
+e_attachment_view_recent_action_new (EAttachmentView *view,
+ const gchar *action_name,
+ const gchar *action_label)
+{
+ GtkAction *action;
+ GtkRecentChooser *chooser;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ action = gtk_recent_action_new (
+ action_name, action_label, NULL, NULL);
+ gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
+
+ chooser = GTK_RECENT_CHOOSER (action);
+ gtk_recent_chooser_set_show_icons (chooser, TRUE);
+ gtk_recent_chooser_set_show_not_found (chooser, FALSE);
+ gtk_recent_chooser_set_show_private (chooser, FALSE);
+ gtk_recent_chooser_set_show_tips (chooser, TRUE);
+ gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
+
+ g_signal_connect (
+ action, "item-activated",
+ G_CALLBACK (action_recent_cb), view);
+
+ return action;
+}
+
+void
+e_attachment_view_show_popup_menu (EAttachmentView *view,
+ GdkEventButton *event)
+{
+ GtkUIManager *ui_manager;
+ GtkWidget *menu;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ if (event != NULL) {
+ GtkTreePath *path;
+
+ path = e_attachment_view_get_path_at_pos (
+ view, event->x, event->y);
+ if (path != NULL) {
+ if (!e_attachment_view_path_is_selected (view, path)) {
+ e_attachment_view_unselect_all (view);
+ e_attachment_view_select_path (view, path);
+ }
+ gtk_tree_path_free (path);
+ } else
+ e_attachment_view_unselect_all (view);
+ }
+
+ e_attachment_view_update_actions (view);
+
+ ui_manager = e_attachment_view_get_ui_manager (view);
+ menu = gtk_ui_manager_get_widget (ui_manager, "/context");
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ if (event != NULL)
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ else
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ 0, gtk_get_current_event_time ());
+}
+
+void
+e_attachment_view_update_actions (EAttachmentView *view)
+{
+ EAttachmentViewPrivate *priv;
+ GFileInfo *file_info;
+ GtkAction *action;
+ GList *selected;
+ guint n_selected;
+ gboolean is_image;
+
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+ priv = e_attachment_view_get_private (view);
+ selected = e_attachment_view_get_selected_attachments (view);
+ n_selected = g_list_length (selected);
+
+ is_image = FALSE;
+ file_info = NULL;
+
+ if (n_selected == 1) {
+ EAttachment *attachment = selected->data;
+ file_info = e_attachment_get_file_info (attachment);
+ is_image = e_attachment_is_image (attachment);
+ }
+
+ action = e_attachment_view_get_action (view, "properties");
+ gtk_action_set_visible (action, n_selected == 1);
+
+ action = e_attachment_view_get_action (view, "remove");
+ gtk_action_set_visible (action, n_selected > 0);
+
+ action = e_attachment_view_get_action (view, "save-as");
+ gtk_action_set_visible (action, n_selected > 0);
+
+ action = e_attachment_view_get_action (view, "set-background");
+ gtk_action_set_visible (action, is_image);
+}
diff --git a/widgets/misc/e-attachment-view.h b/widgets/misc/e-attachment-view.h
new file mode 100644
index 0000000000..a00308d2d5
--- /dev/null
+++ b/widgets/misc/e-attachment-view.h
@@ -0,0 +1,163 @@
+/*
+ * e-attachment-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_VIEW_H
+#define E_ATTACHMENT_VIEW_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment-store.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_VIEW \
+ (e_attachment_view_get_type ())
+#define E_ATTACHMENT_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_VIEW, EAttachmentView))
+#define E_ATTACHMENT_VIEW_IFACE(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_VIEW, EAttachmentViewIface))
+#define E_IS_ATTACHMENT_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_VIEW))
+#define E_IS_ATTACHMENT_VIEW_IFACE(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_VIEW))
+#define E_ATTACHMENT_VIEW_GET_IFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE \
+ ((obj), E_TYPE_ATTACHMENT_VIEW, EAttachmentViewIface))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentView EAttachmentView;
+typedef struct _EAttachmentViewIface EAttachmentViewIface;
+typedef struct _EAttachmentViewPrivate EAttachmentViewPrivate;
+
+struct _EAttachmentViewIface {
+ GTypeInterface parent_iface;
+
+ /* General Methods */
+ EAttachmentViewPrivate *
+ (*get_private) (EAttachmentView *view);
+ EAttachmentStore *
+ (*get_store) (EAttachmentView *view);
+
+ /* Selection Methods */
+ GtkTreePath * (*get_path_at_pos) (EAttachmentView *view,
+ gint x,
+ gint y);
+ GList * (*get_selected_paths) (EAttachmentView *view);
+ gboolean (*path_is_selected) (EAttachmentView *view,
+ GtkTreePath *path);
+ void (*select_path) (EAttachmentView *view,
+ GtkTreePath *path);
+ void (*unselect_path) (EAttachmentView *view,
+ GtkTreePath *path);
+ void (*select_all) (EAttachmentView *view);
+ void (*unselect_all) (EAttachmentView *view);
+};
+
+struct _EAttachmentViewPrivate {
+
+ /* Popup Menu Management */
+ GtkUIManager *ui_manager;
+ GtkActionGroup *standard_actions;
+ GtkActionGroup *editable_actions;
+ GtkActionGroup *openwith_actions;
+ guint merge_id;
+
+ /* Drag and Drop State */
+ GdkDragContext *drag_context;
+ GtkSelectionData *selection_data;
+ guint info;
+ guint time;
+};
+
+GType e_attachment_view_get_type (void);
+
+void e_attachment_view_init (EAttachmentView *view);
+void e_attachment_view_dispose (EAttachmentView *view);
+void e_attachment_view_finalize (EAttachmentView *view);
+
+EAttachmentViewPrivate *
+ e_attachment_view_get_private (EAttachmentView *view);
+EAttachmentStore *
+ e_attachment_view_get_store (EAttachmentView *view);
+GList * e_attachment_view_get_selected_attachments
+ (EAttachmentView *view);
+void e_attachment_view_remove_selected
+ (EAttachmentView *view,
+ gboolean select_next);
+
+/* Selection Management */
+GtkTreePath * e_attachment_view_get_path_at_pos
+ (EAttachmentView *view,
+ gint x,
+ gint y);
+GList * e_attachment_view_get_selected_paths
+ (EAttachmentView *view);
+gboolean e_attachment_view_path_is_selected
+ (EAttachmentView *view,
+ GtkTreePath *path);
+void e_attachment_view_select_path (EAttachmentView *view,
+ GtkTreePath *path);
+void e_attachment_view_unselect_path (EAttachmentView *view,
+ GtkTreePath *path);
+void e_attachment_view_select_all (EAttachmentView *view);
+void e_attachment_view_unselect_all (EAttachmentView *view);
+void e_attachment_view_sync_selection(EAttachmentView *view,
+ EAttachmentView *target);
+
+/* Drag and Drop Support */
+void e_attachment_view_drag_action (EAttachmentView *view,
+ GdkDragAction action);
+gboolean e_attachment_view_drag_motion (EAttachmentView *view,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time);
+void e_attachment_view_drag_data_received
+ (EAttachmentView *view,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time);
+
+/* Popup Menu Management */
+GtkAction * e_attachment_view_get_action (EAttachmentView *view,
+ const gchar *action_name);
+GtkActionGroup *e_attachment_view_get_action_group
+ (EAttachmentView *view,
+ const gchar *group_name);
+GtkUIManager * e_attachment_view_get_ui_manager(EAttachmentView *view);
+GtkAction * e_attachment_view_recent_action_new
+ (EAttachmentView *view,
+ const gchar *action_name,
+ const gchar *action_label);
+void e_attachment_view_show_popup_menu
+ (EAttachmentView *view,
+ GdkEventButton *event);
+void e_attachment_view_update_actions(EAttachmentView *view);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_VIEW_H */
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index 9bb6f09ade..6f9e80f02b 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -1,4 +1,5 @@
/*
+ * e-attachment.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,81 +15,275 @@
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore@ximian.com>
- * Jeffrey Stedfast <fejj@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
#include "e-attachment.h"
-#include "e-attachment-dialog.h"
-
-#ifdef G_OS_WIN32
-/* Include <windows.h> early (as the gio stuff below will
- * include it anyway, sigh) to workaround the DATADIR problem.
- * <windows.h> (and the headers it includes) stomps all over the
- * namespace like a baboon on crack, and especially the DATADIR enum
- * in objidl.h causes problems.
- */
-#undef DATADIR
-#define DATADIR crap_DATADIR
-#include <windows.h>
-#undef DATADIR
-#endif
-#include <sys/stat.h>
-#include <string.h>
#include <errno.h>
-
-#include <camel/camel.h>
-
#include <glib/gi18n.h>
-#include <glib/gstdio.h>
-
-#include <libebook/e-vcard.h>
+#include <camel/camel-iconv.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-vfs.h>
#include "e-util/e-util.h"
-#include "e-util/e-error.h"
-#include "e-util/e-mktemp.h"
-#include "e-util/e-util-private.h"
#define E_ATTACHMENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
+/* Attributes needed by EAttachmentStore, et al. */
+#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*"
+
struct _EAttachmentPrivate {
- gchar *filename;
- gchar *description;
+ GFile *file;
+ GFileInfo *file_info;
+ GCancellable *cancellable;
+ CamelMimePart *mime_part;
gchar *disposition;
- gchar *mime_type;
- GdkPixbuf *thumbnail;
- CamelMimePart *mime_part;
+ /* This is a reference to our row in an EAttachmentStore,
+ * serving as a means of broadcasting "row-changed" signals.
+ * If we are removed from the store, we lazily free the
+ * reference when it is found to be to be invalid. */
+ GtkTreeRowReference *reference;
};
enum {
PROP_0,
- PROP_DESCRIPTION,
PROP_DISPOSITION,
- PROP_FILENAME,
- PROP_THUMBNAIL
-};
-
-enum {
- CHANGED,
- UPDATE,
- LAST_SIGNAL
+ PROP_FILE,
+ PROP_FILE_INFO,
+ PROP_MIME_PART
};
static gpointer parent_class;
-static guint signals[LAST_SIGNAL];
+
+static void
+attachment_notify_model (EAttachment *attachment)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ reference = attachment->priv->reference;
+
+ if (reference == NULL)
+ return;
+
+ /* Free the reference if it's no longer valid.
+ * It means we've been removed from the store. */
+ if (!gtk_tree_row_reference_valid (reference)) {
+ gtk_tree_row_reference_free (reference);
+ attachment->priv->reference = NULL;
+ return;
+ }
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_row_changed (model, path, &iter);
+ g_object_notify (G_OBJECT (model), "total-size");
+
+ gtk_tree_path_free (path);
+}
+
+static gchar *
+attachment_get_default_charset (void)
+{
+ GConfClient *client;
+ const gchar *key;
+ gchar *charset;
+
+ /* XXX This function doesn't really belong here. */
+
+ client = gconf_client_get_default ();
+ key = "/apps/evolution/mail/composer/charset";
+ charset = gconf_client_get_string (client, key, NULL);
+ if (charset == NULL || *charset == '\0') {
+ g_free (charset);
+ key = "/apps/evolution/mail/format/charset";
+ charset = gconf_client_get_string (client, key, NULL);
+ if (charset == NULL || *charset == '\0') {
+ g_free (charset);
+ charset = NULL;
+ }
+ }
+ g_object_unref (client);
+
+ if (charset == NULL)
+ charset = g_strdup (camel_iconv_locale_charset ());
+
+ if (charset == NULL)
+ charset = g_strdup ("us-ascii");
+
+ return charset;
+}
+
+static void
+attachment_set_file_info (EAttachment *attachment,
+ GFileInfo *file_info)
+{
+ GCancellable *cancellable;
+
+ cancellable = attachment->priv->cancellable;
+
+ /* Cancel any query operations in progress. */
+ if (!g_cancellable_is_cancelled (cancellable)) {
+ g_cancellable_cancel (cancellable);
+ g_cancellable_reset (cancellable);
+ }
+
+ if (file_info != NULL)
+ g_object_ref (file_info);
+
+ if (attachment->priv->file_info != NULL)
+ g_object_unref (attachment->priv->file_info);
+
+ attachment->priv->file_info = file_info;
+
+ g_object_notify (G_OBJECT (attachment), "file-info");
+
+ attachment_notify_model (attachment);
+}
+
+static void
+attachment_reset (EAttachment *attachment)
+{
+ GCancellable *cancellable;
+
+ cancellable = attachment->priv->cancellable;
+
+ g_object_freeze_notify (G_OBJECT (attachment));
+
+ /* Cancel any query operations in progress. */
+ if (!g_cancellable_is_cancelled (cancellable)) {
+ g_cancellable_cancel (cancellable);
+ g_cancellable_reset (cancellable);
+ }
+
+ if (attachment->priv->file != NULL) {
+ g_object_notify (G_OBJECT (attachment), "file");
+ g_object_unref (attachment->priv->file);
+ attachment->priv->file = NULL;
+ }
+
+ if (attachment->priv->mime_part != NULL) {
+ g_object_notify (G_OBJECT (attachment), "mime-part");
+ g_object_unref (attachment->priv->mime_part);
+ attachment->priv->mime_part = NULL;
+ }
+
+ attachment_set_file_info (attachment, NULL);
+
+ g_object_thaw_notify (G_OBJECT (attachment));
+}
+
+static void
+attachment_file_info_ready_cb (GFile *file,
+ GAsyncResult *result,
+ EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ GError *error = NULL;
+
+ /* Even if we failed to obtain a GFileInfo, we still emit a
+ * "notify::file-info" to signal the async operation finished. */
+ file_info = g_file_query_info_finish (file, result, &error);
+ attachment_set_file_info (attachment, file_info);
+
+ if (file_info != NULL)
+ g_object_unref (file_info);
+ else {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+attachment_file_info_to_mime_part (EAttachment *attachment,
+ CamelMimePart *mime_part)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
+ const gchar *string;
+ gchar *allocated;
+
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info == NULL || mime_part == NULL)
+ return;
+
+ /* XXX Note that we skip "standard::size" here. */
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+ string = g_file_info_get_attribute_string (file_info, attribute);
+ allocated = g_content_type_get_mime_type (string);
+ camel_mime_part_set_content_type (mime_part, allocated);
+ g_free (allocated);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+ string = g_file_info_get_attribute_string (file_info, attribute);
+ camel_mime_part_set_filename (mime_part, string);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ string = g_file_info_get_attribute_string (file_info, attribute);
+ camel_mime_part_set_description (mime_part, string);
+
+ string = e_attachment_get_disposition (attachment);
+ camel_mime_part_set_disposition (mime_part, string);
+}
+
+static void
+attachment_mime_part_to_file_info (EAttachment *attachment)
+{
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
+ GFileInfo *file_info;
+ const gchar *attribute;
+ const gchar *string;
+ gchar *allocated;
+ guint64 v_uint64;
+
+ file_info = e_attachment_get_file_info (attachment);
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ if (file_info == NULL || mime_part == NULL)
+ return;
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+ content_type = camel_mime_part_get_content_type (mime_part);
+ allocated = camel_content_type_simple (content_type);
+ if (allocated != NULL)
+ g_file_info_set_attribute_string (
+ file_info, attribute, allocated);
+ g_free (allocated);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+ string = camel_mime_part_get_filename (mime_part);
+ if (string != NULL)
+ g_file_info_set_attribute_string (
+ file_info, attribute, string);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ string = camel_mime_part_get_description (mime_part);
+ if (string != NULL)
+ g_file_info_set_attribute_string (
+ file_info, attribute, string);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_SIZE;
+ v_uint64 = camel_mime_part_get_content_size (mime_part);
+ g_file_info_set_attribute_uint64 (file_info, attribute, v_uint64);
+
+ string = camel_mime_part_get_disposition (mime_part);
+ e_attachment_set_disposition (attachment, string);
+}
static void
attachment_set_property (GObject *object,
@@ -97,28 +292,22 @@ attachment_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_DESCRIPTION:
- e_attachment_set_description (
- E_ATTACHMENT (object),
- g_value_get_string (value));
- return;
-
case PROP_DISPOSITION:
e_attachment_set_disposition (
E_ATTACHMENT (object),
g_value_get_string (value));
return;
- case PROP_FILENAME:
- e_attachment_set_filename (
+ case PROP_FILE:
+ e_attachment_set_file (
E_ATTACHMENT (object),
- g_value_get_string (value));
+ g_value_get_object (value));
return;
- case PROP_THUMBNAIL:
- e_attachment_set_thumbnail (
+ case PROP_MIME_PART:
+ e_attachment_set_mime_part (
E_ATTACHMENT (object),
- g_value_get_object (value));
+ g_value_get_boxed (value));
return;
}
@@ -132,27 +321,27 @@ attachment_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_DESCRIPTION:
- g_value_set_string (
- value, e_attachment_get_description (
- E_ATTACHMENT (object)));
- return;
-
case PROP_DISPOSITION:
g_value_set_string (
value, e_attachment_get_disposition (
E_ATTACHMENT (object)));
return;
- case PROP_FILENAME:
- g_value_set_string (
- value, e_attachment_get_filename (
+ case PROP_FILE:
+ g_value_set_object (
+ value, e_attachment_get_file (
E_ATTACHMENT (object)));
return;
- case PROP_THUMBNAIL:
+ case PROP_FILE_INFO:
g_value_set_object (
- value, e_attachment_get_thumbnail (
+ value, e_attachment_get_file_info (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_MIME_PART:
+ g_value_set_boxed (
+ value, e_attachment_get_mime_part (
E_ATTACHMENT (object)));
return;
}
@@ -167,9 +356,20 @@ attachment_dispose (GObject *object)
priv = E_ATTACHMENT_GET_PRIVATE (object);
- if (priv->thumbnail != NULL) {
- g_object_unref (priv->thumbnail);
- priv->thumbnail = NULL;
+ if (priv->cancellable != NULL) {
+ g_cancellable_cancel (priv->cancellable);
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
+ }
+
+ if (priv->file != NULL) {
+ g_object_unref (priv->file);
+ priv->file = NULL;
+ }
+
+ if (priv->file_info != NULL) {
+ g_object_unref (priv->file_info);
+ priv->file_info = NULL;
}
if (priv->mime_part != NULL) {
@@ -177,6 +377,10 @@ attachment_dispose (GObject *object)
priv->mime_part = NULL;
}
+ /* This accepts NULL arguments. */
+ gtk_tree_row_reference_free (priv->reference);
+ priv->reference = NULL;
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -184,20 +388,11 @@ attachment_dispose (GObject *object)
static void
attachment_finalize (GObject *object)
{
- EAttachment *attachment = (EAttachment *) object;
-
- if (attachment->cancellable) {
- /* the operation is still running, so cancel it */
- g_cancellable_cancel (attachment->cancellable);
- attachment->cancellable = NULL;
- }
+ EAttachmentPrivate *priv;
- g_free (attachment->store_uri);
+ priv = E_ATTACHMENT_GET_PRIVATE (object);
- g_free (attachment->priv->filename);
- g_free (attachment->priv->description);
- g_free (attachment->priv->disposition);
- g_free (attachment->priv->mime_type);
+ g_free (priv->disposition);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -219,75 +414,52 @@ attachment_class_init (EAttachmentClass *class)
g_object_class_install_property (
object_class,
- PROP_DESCRIPTION,
+ PROP_DISPOSITION,
g_param_spec_string (
- "description",
- "Description",
- NULL,
+ "disposition",
+ "Disposition",
NULL,
+ "attachment",
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (
object_class,
- PROP_DESCRIPTION,
- g_param_spec_string (
- "disposition",
- "Disposition",
- NULL,
+ PROP_FILE,
+ g_param_spec_object (
+ "file",
+ "File",
NULL,
+ G_TYPE_FILE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (
object_class,
- PROP_DESCRIPTION,
- g_param_spec_string (
- "filename",
- "Filename",
- NULL,
+ PROP_FILE_INFO,
+ g_param_spec_object (
+ "file-info",
+ "File Info",
NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
+ G_TYPE_FILE_INFO,
+ G_PARAM_READABLE));
g_object_class_install_property (
object_class,
- PROP_THUMBNAIL,
- g_param_spec_object (
- "thumbnail",
- "Thumbnail Image",
+ PROP_MIME_PART,
+ g_param_spec_boxed (
+ "mime-part",
+ "MIME Part",
NULL,
- GDK_TYPE_PIXBUF,
+ E_TYPE_CAMEL_OBJECT,
G_PARAM_READWRITE));
-
- signals[CHANGED] = g_signal_new (
- "changed",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- signals[UPDATE] = g_signal_new (
- "update",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, update),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
}
static void
attachment_init (EAttachment *attachment)
{
attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
-
- attachment->index = -1;
- attachment->percentage = -1;
- attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
- attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
+ attachment->priv->cancellable = g_cancellable_new ();
}
GType
@@ -316,711 +488,845 @@ e_attachment_get_type (void)
return type;
}
-/**
- * file_ext_is:
- * @param filename: path for file
- * @param ext: desired extension, with a dot
- * @return if filename has extension ext or not
- **/
-
-static gboolean
-file_ext_is (const char *filename, const char *ext)
+EAttachment *
+e_attachment_new (void)
{
- int i, dot = -1;
+ return g_object_new (E_TYPE_ATTACHMENT, NULL);
+}
- if (!filename || !ext)
- return FALSE;
+EAttachment *
+e_attachment_new_for_path (const gchar *path)
+{
+ EAttachment *attachment;
+ GFile *file;
- for (i = 0; filename[i]; i++) {
- if (filename [i] == '.')
- dot = i;
- }
+ g_return_val_if_fail (path != NULL, NULL);
- if (dot > 0) {
- return 0 == g_ascii_strcasecmp (filename + dot, ext);
- }
+ file = g_file_new_for_path (path);
+ attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+ g_object_unref (file);
- return FALSE;
+ return attachment;
}
-static char *
-attachment_guess_mime_type (const char *filename)
+EAttachment *
+e_attachment_new_for_uri (const gchar *uri)
{
- char *type;
- gchar *content = NULL;
+ EAttachment *attachment;
+ GFile *file;
- type = e_util_guess_mime_type (filename, TRUE);
+ g_return_val_if_fail (uri != NULL, NULL);
- if (type && strcmp (type, "text/directory") == 0 &&
- file_ext_is (filename, ".vcf") &&
- g_file_get_contents (filename, &content, NULL, NULL) &&
- content) {
- EVCard *vc = e_vcard_new_from_string (content);
+ file = g_file_new_for_uri (uri);
+ attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+ g_object_unref (file);
- if (vc) {
- g_free (type);
- g_object_unref (G_OBJECT (vc));
+ return attachment;
+}
- type = g_strdup ("text/x-vcard");
- }
+EAttachment *
+e_attachment_new_for_message (CamelMimeMessage *message)
+{
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ EAttachment *attachment;
+ GString *description;
+ const gchar *subject;
- }
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
- g_free (content);
+ mime_part = camel_mime_part_new ();
+ camel_mime_part_set_disposition (mime_part, "inline");
+ subject = camel_mime_message_get_subject (message);
- if (type) {
- /* Check if returned mime_type is valid */
- CamelContentType *ctype = camel_content_type_decode (type);
+ description = g_string_new (_("Attached message"));
+ if (subject != NULL)
+ g_string_append_printf (description, " - %s", subject);
+ camel_mime_part_set_description (mime_part, description->str);
+ g_string_free (description, TRUE);
- if (!ctype) {
- g_free (type);
- type = NULL;
- } else
- camel_content_type_unref (ctype);
- }
+ wrapper = CAMEL_DATA_WRAPPER (message);
+ camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+ camel_mime_part_set_content_type (mime_part, "message/rfc822");
- return type;
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ camel_object_unref (mime_part);
+
+ return attachment;
}
-
-/**
- * e_attachment_new:
- * @filename: filename to attach
- * @disposition: Content-Disposition of the attachment
- * @ex: exception
- *
- * Return value: the new attachment, or %NULL on error
- **/
-EAttachment *
-e_attachment_new (const char *filename, const char *disposition, CamelException *ex)
+void
+e_attachment_add_to_multipart (EAttachment *attachment,
+ CamelMultipart *multipart,
+ const gchar *default_charset)
{
- EAttachment *new;
- CamelMimePart *part;
+ CamelContentType *content_type;
CamelDataWrapper *wrapper;
- CamelStream *stream;
- struct stat statbuf;
- gchar *mime_type;
- gchar *basename;
- CamelURL *url;
+ CamelMimePart *mime_part;
- g_return_val_if_fail (filename != NULL, NULL);
+ /* XXX EMsgComposer might be a better place for this function. */
- if (g_stat (filename, &statbuf) < 0) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- filename, g_strerror (errno));
- return NULL;
- }
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
- /* return if it's not a regular file */
- if (!S_ISREG (statbuf.st_mode)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: not a regular file"),
- filename);
- return NULL;
- }
+ /* Still loading? Too bad. */
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part == NULL)
+ return;
- if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- filename, g_strerror (errno));
- return NULL;
- }
+ content_type = camel_mime_part_get_content_type (mime_part);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ if (CAMEL_IS_MULTIPART (wrapper))
+ goto exit;
- if ((mime_type = attachment_guess_mime_type (filename))) {
- if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
- wrapper = (CamelDataWrapper *) camel_mime_message_new ();
- } else {
- wrapper = camel_data_wrapper_new ();
+ /* For text content, determine the best encoding and character set. */
+ if (camel_content_type_is (content_type, "text", "*")) {
+ CamelTransferEncoding encoding;
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilterBestenc *filter;
+ CamelStream *stream;
+ const gchar *charset;
+
+ charset = camel_content_type_param (content_type, "charset");
+
+ /* Determine the best encoding by writing the MIME
+ * part to a NULL stream with a "bestenc" filter. */
+ stream = camel_stream_null_new ();
+ filtered_stream = camel_stream_filter_new_with_stream (stream);
+ filter = camel_mime_filter_bestenc_new (
+ CAMEL_BESTENC_GET_ENCODING);
+ camel_stream_filter_add (
+ filtered_stream, CAMEL_MIME_FILTER (filter));
+ camel_data_wrapper_decode_to_stream (
+ wrapper, CAMEL_STREAM (filtered_stream));
+ camel_object_unref (filtered_stream);
+ camel_object_unref (stream);
+
+ /* Retrieve the best encoding from the filter. */
+ encoding = camel_mime_filter_bestenc_get_best_encoding (
+ filter, CAMEL_BESTENC_8BIT);
+ camel_mime_part_set_encoding (mime_part, encoding);
+ camel_object_unref (filter);
+
+ if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
+ /* The text fits within us-ascii, so this is safe.
+ * FIXME Check that this isn't iso-2022-jp? */
+ default_charset = "us-ascii";
+
+ } else if (charset == NULL && default_charset == NULL) {
+ default_charset = attachment_get_default_charset ();
+ /* FIXME Check that this fits within the
+ * default_charset and if not, find one
+ * that does and/or allow the user to
+ * specify. */
}
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
- g_free (mime_type);
- } else {
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
- }
+ if (charset == NULL) {
+ gchar *type;
- camel_object_unref (stream);
+ camel_content_type_set_param (
+ content_type, "charset", default_charset);
+ type = camel_content_type_format (content_type);
+ camel_mime_part_set_content_type (mime_part, type);
+ g_free (type);
+ }
- part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
- camel_object_unref (wrapper);
+ /* Otherwise, unless it's a message/rfc822, Base64 encode it. */
+ } else if (!CAMEL_IS_MIME_MESSAGE (wrapper))
+ camel_mime_part_set_encoding (
+ mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
- camel_mime_part_set_disposition (part, disposition);
- basename = g_path_get_basename (filename);
- camel_mime_part_set_filename (part, basename);
+exit:
+ camel_multipart_add_part (multipart, mime_part);
+}
-#if 0
- /* Note: Outlook 2002 is broken with respect to Content-Ids on
- non-multipart/related parts, so as an interoperability
- workaround, don't set a Content-Id on these parts. Fixes
- bug #10032 */
- /* set the Content-Id */
- content_id = camel_header_msgid_generate ();
- camel_mime_part_set_content_id (part, content_id);
- g_free (content_id);
-#endif
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- 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;
+ return attachment->priv->disposition;
+}
+
+void
+e_attachment_set_disposition (EAttachment *attachment,
+ const gchar *disposition)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, filename);
- new->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
+ g_free (attachment->priv->disposition);
+ attachment->priv->disposition = g_strdup (disposition);
- return new;
+ g_object_notify (G_OBJECT (attachment), "disposition");
}
+GFile *
+e_attachment_get_file (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
-typedef struct {
- EAttachment *attachment;
- char *filename;
- char *uri;
- GtkWindow *parent; /* for error dialog */
-
- guint64 file_size; /* zero indicates unknown size */
- GInputStream *istream; /* read from here ... */
- GOutputStream *ostream; /* ...and write into this. */
- gboolean was_error;
+ return attachment->priv->file;
+}
+
+void
+e_attachment_set_file (EAttachment *attachment,
+ GFile *file)
+{
GCancellable *cancellable;
- void *buffer; /* read into this, not more than buffer_size bytes */
- gsize buffer_size;
-} DownloadInfo;
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
-static void
-download_info_free (DownloadInfo *download_info)
-{
- /* if there was an error, then free attachment too */
- if (download_info->was_error)
- g_object_unref (download_info->attachment);
+ g_object_freeze_notify (G_OBJECT (attachment));
+
+ if (file != NULL) {
+ g_return_if_fail (G_IS_FILE (file));
+ g_object_ref (file);
+ }
+
+ attachment_reset (attachment);
+ attachment->priv->file = file;
- if (download_info->ostream)
- g_object_unref (download_info->ostream);
+ cancellable = attachment->priv->cancellable;
- if (download_info->istream)
- g_object_unref (download_info->istream);
+ if (file != NULL)
+ g_file_query_info_async (
+ file, ATTACHMENT_QUERY,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback)
+ attachment_file_info_ready_cb,
+ attachment);
- if (download_info->cancellable)
- g_object_unref (download_info->cancellable);
+ g_object_notify (G_OBJECT (attachment), "file");
- g_free (download_info->filename);
- g_free (download_info->uri);
- g_free (download_info->buffer);
- g_free (download_info);
+ g_object_thaw_notify (G_OBJECT (attachment));
}
-static void
-data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+GFileInfo *
+e_attachment_get_file_info (EAttachment *attachment)
{
- DownloadInfo *download_info = (DownloadInfo *)user_data;
- GError *error = NULL;
- gssize read;
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- g_return_if_fail (download_info != NULL);
+ return attachment->priv->file_info;
+}
- if (g_cancellable_is_cancelled (download_info->cancellable)) {
- /* finish the operation and close both streams */
- g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL);
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- g_output_stream_close (download_info->ostream, NULL, NULL);
- g_input_stream_close (download_info->istream, NULL, NULL);
+ return attachment->priv->mime_part;
+}
- /* The only way how to get this canceled is in EAttachment's finalize method,
- and because the download_info_free free's the attachment on error,
- then do not consider cancellation as an error. */
- download_info_free (download_info);
- return;
+void
+e_attachment_set_mime_part (EAttachment *attachment,
+ CamelMimePart *mime_part)
+{
+ GFileInfo *file_info;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_object_freeze_notify (G_OBJECT (attachment));
+
+ if (mime_part != NULL) {
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ camel_object_ref (mime_part);
}
- read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
+ attachment_reset (attachment);
+ attachment->priv->mime_part = mime_part;
- if (!error)
- g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error);
+ file_info = g_file_info_new ();
+ attachment_set_file_info (attachment, file_info);
+ attachment_mime_part_to_file_info (attachment);
+ g_object_unref (file_info);
- if (error) {
- download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED;
- if (download_info->was_error)
- e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL);
+ g_object_notify (G_OBJECT (attachment), "mime-part");
- g_error_free (error);
+ g_object_thaw_notify (G_OBJECT (attachment));
+}
- download_info->attachment->cancellable = NULL;
- download_info_free (download_info);
- return;
- }
+const gchar *
+e_attachment_get_content_type (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
- if (read == 0) {
- CamelException ex;
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- /* done with reading */
- g_output_stream_close (download_info->ostream, NULL, NULL);
- g_input_stream_close (download_info->istream, NULL, NULL);
+ attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+ file_info = e_attachment_get_file_info (attachment);
- download_info->attachment->cancellable = NULL;
+ if (file_info == NULL)
+ return NULL;
- camel_exception_init (&ex);
- e_attachment_build_remote_file (download_info->filename, download_info->attachment, &ex);
+ return g_file_info_get_attribute_string (file_info, attribute);
+}
- if (camel_exception_is_set (&ex)) {
- download_info->was_error = TRUE;
- e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
- }
+const gchar *
+e_attachment_get_display_name (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
- download_info->attachment->percentage = -1;
- download_info->attachment->is_available_local = TRUE;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- download_info_free (download_info);
- return;
- } else if (download_info->file_size) {
- download_info->attachment->percentage = read * 100 / download_info->file_size;
- download_info->file_size -= MIN (download_info->file_size, read);
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
- } else {
- download_info->attachment->percentage = 0;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
- }
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
+ file_info = e_attachment_get_file_info (attachment);
- /* read next chunk */
- g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+ if (file_info == NULL)
+ return NULL;
+
+ return g_file_info_get_attribute_string (file_info, attribute);
}
-static gboolean
-download_to_local_path (DownloadInfo *download_info, CamelException *ex)
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
{
- GError *error = NULL;
- GFile *src = g_file_new_for_uri (download_info->uri);
- GFile *des = g_file_new_for_path (download_info->filename);
- gboolean res = FALSE;
+ GFileInfo *file_info;
+ const gchar *attribute;
- g_return_val_if_fail (src != NULL && des != NULL, FALSE);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ file_info = e_attachment_get_file_info (attachment);
- if (download_info->ostream && !error) {
- GFileInfo *fi;
+ if (file_info == NULL)
+ return NULL;
- fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ return g_file_info_get_attribute_string (file_info, attribute);
+}
- if (fi) {
- download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE);
- g_object_unref (fi);
- } else {
- download_info->file_size = 0;
- }
+GIcon *
+e_attachment_get_icon (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
- download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error));
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- if (download_info->istream && !error) {
- download_info->cancellable = g_cancellable_new ();
- download_info->attachment->cancellable = download_info->cancellable;
- download_info->buffer_size = 10240; /* max 10KB chunk */
- download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size);
+ attribute = G_FILE_ATTRIBUTE_STANDARD_ICON;
+ file_info = e_attachment_get_file_info (attachment);
- g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+ if (file_info == NULL)
+ return NULL;
- res = TRUE;
- }
- }
+ return (GIcon *)
+ g_file_info_get_attribute_object (file_info, attribute);
+}
+
+const gchar *
+e_attachment_get_thumbnail_path (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
- if (error) {
- /* propagate error */
- if (ex)
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- g_error_free (error);
- download_info->was_error = TRUE;
- download_info_free (download_info);
- }
+ attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH;
+ file_info = e_attachment_get_file_info (attachment);
- g_object_unref (src);
- g_object_unref (des);
+ if (file_info == NULL)
+ return NULL;
- return res;
+ return g_file_info_get_attribute_byte_string (file_info, attribute);
}
-EAttachment *
-e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, const char *disposition, const char *path, CamelException *ex)
+guint64
+e_attachment_get_size (EAttachment *attachment)
{
- EAttachment *new;
- DownloadInfo *download_info;
- CamelURL *url;
- char *base;
- gchar *filename;
+ GFileInfo *file_info;
+ const gchar *attribute;
- g_return_val_if_fail (uri != NULL, NULL);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0);
- url = camel_url_new (uri, NULL);
- base = g_path_get_basename (url->path);
- camel_url_free (url);
+ attribute = G_FILE_ATTRIBUTE_STANDARD_SIZE;
+ file_info = e_attachment_get_file_info (attachment);
- filename = g_build_filename (path, base, NULL);
+ if (file_info == NULL)
+ return 0;
- 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;
+ return g_file_info_get_attribute_uint64 (file_info, attribute);
+}
- g_free (base);
+gboolean
+e_attachment_is_image (EAttachment *attachment)
+{
+ const gchar *content_type;
- download_info = g_new0 (DownloadInfo, 1);
- download_info->attachment = new;
- download_info->filename = g_strdup (filename);
- download_info->uri = g_strdup (uri);
- download_info->parent = error_dlg_parent;
- download_info->was_error = FALSE;
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
- g_free (filename);
+ content_type = e_attachment_get_content_type (attachment);
- /* it frees all on the error, so do not free it twice */
- if (!download_to_local_path (download_info, ex))
- return NULL;
+ if (content_type == NULL)
+ return FALSE;
- return new;
+ return g_content_type_is_a (content_type, "image");
}
-
-void
-e_attachment_build_remote_file (const gchar *filename,
- EAttachment *attachment,
- CamelException *ex)
+gboolean
+e_attachment_is_rfc822 (EAttachment *attachment)
{
- CamelMimePart *part;
- CamelDataWrapper *wrapper;
- CamelStream *stream;
- struct stat statbuf;
- const gchar *description;
- const gchar *disposition;
- gchar *mime_type;
- gchar *basename;
- CamelURL *url;
+ const gchar *content_type;
- g_return_if_fail (filename != NULL);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
- if (g_stat (filename, &statbuf) == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- filename, g_strerror (errno));
- g_message ("Cannot attach file %s: %s\n", filename, g_strerror (errno));
- return;
- }
+ content_type = e_attachment_get_content_type (attachment);
- /* return if it's not a regular file */
- if (!S_ISREG (statbuf.st_mode)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: not a regular file"),
- filename);
- g_message ("Cannot attach file %s: not a regular file", filename);
- return;
- }
+ if (content_type == NULL)
+ return FALSE;
- if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- filename, g_strerror (errno));
- return;
- }
+ return g_content_type_equals (content_type, "message/rfc822");
+}
- if ((mime_type = attachment_guess_mime_type (filename))) {
- if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
- wrapper = (CamelDataWrapper *) camel_mime_message_new ();
- } else {
- wrapper = camel_data_wrapper_new ();
- }
+static void
+attachment_save_file_cb (GFile *source,
+ GAsyncResult *result,
+ EActivity *activity)
+{
+ GError *error = NULL;
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
- g_free (mime_type);
- } else {
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
+ if (!g_file_copy_finish (source, result, &error)) {
+ e_activity_set_error (activity, error);
+ g_error_free (error);
}
- camel_object_unref (stream);
+ e_activity_complete (activity);
+ g_object_unref (activity);
+}
- part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
- camel_object_unref (wrapper);
+static gpointer
+attachment_save_part_thread (EActivity *activity)
+{
+ GObject *object;
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GOutputStream *output_stream;
+ EFileActivity *file_activity;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ CamelStream *stream;
+ GError *error = NULL;
- disposition = e_attachment_get_disposition (attachment);
- camel_mime_part_set_disposition (part, disposition);
+ object = G_OBJECT (activity);
+ attachment = g_object_get_data (object, "attachment");
+ output_stream = g_object_get_data (object, "output-stream");
- if (e_attachment_get_filename (attachment) == NULL)
- basename = g_path_get_basename (filename);
- else
- basename = g_path_get_basename (e_attachment_get_filename (attachment));
+ /* Last chance to cancel. */
+ file_activity = E_FILE_ACTIVITY (activity);
+ cancellable = e_file_activity_get_cancellable (file_activity);
+ if (g_cancellable_set_error_if_cancelled (cancellable, &error))
+ goto exit;
- camel_mime_part_set_filename (part, filename);
+ object = g_object_ref (output_stream);
+ stream = camel_stream_vfs_new_with_stream (object);
+ mime_part = e_attachment_get_mime_part (attachment);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
- description = e_attachment_get_description (attachment);
- if (description != NULL) {
- camel_mime_part_set_description (part, description);
- e_attachment_set_description (attachment, NULL);
- }
+ if (camel_data_wrapper_decode_to_stream (wrapper, stream) < 0)
+ g_set_error (
+ &error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ g_strerror (errno));
- attachment->priv->mime_part = part;
- attachment->size = statbuf.st_size;
- attachment->guessed_type = TRUE;
+ else if (camel_stream_flush (stream) < 0)
+ g_set_error (
+ &error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ g_strerror (errno));
- e_attachment_set_filename (attachment, basename);
+ camel_object_unref (stream);
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, filename);
- attachment->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
+exit:
+ if (error != NULL) {
+ e_activity_set_error (activity, error);
+ g_error_free (error);
+ }
- g_free (basename);
-}
+ e_activity_complete_in_idle (activity);
+ g_object_unref (activity);
+ return NULL;
+}
-/**
- * e_attachment_new_from_mime_part:
- * @part: a CamelMimePart
- *
- * Return value: a new EAttachment based on the mime part
- **/
-EAttachment *
-e_attachment_new_from_mime_part (CamelMimePart *part)
+static void
+attachment_save_part_cb (GFile *destination,
+ GAsyncResult *result,
+ EActivity *activity)
{
- EAttachment *new;
- const gchar *filename;
+ GFileOutputStream *output_stream;
+ GError *error = NULL;
- g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+ output_stream = g_file_replace_finish (destination, result, &error);
- filename = camel_mime_part_get_filename (part);
+ if (output_stream != NULL) {
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "output-stream", output_stream,
+ (GDestroyNotify) g_object_unref);
+ g_thread_create (
+ (GThreadFunc) attachment_save_part_thread,
+ activity, FALSE, &error);
+ }
- new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
- camel_object_ref (part);
- new->priv->mime_part = part;
- new->guessed_type = FALSE;
- new->is_available_local = TRUE;
- new->size = camel_mime_part_get_content_size (part);
+ if (error != NULL) {
+ e_activity_set_error (activity, error);
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ g_error_free (error);
+ }
- return new;
}
void
-e_attachment_edit (EAttachment *attachment,
- GtkWindow *parent)
+e_attachment_save_async (EAttachment *attachment,
+ EFileActivity *file_activity,
+ GFile *destination)
{
- GtkWidget *dialog;
+ GFileProgressCallback progress_callback;
+ GCancellable *cancellable;
+ CamelMimePart *mime_part;
+ GFile *source;
g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (G_IS_FILE (destination));
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ /* The attachment content is either a GFile (on disk) or a
+ * CamelMimePart (in memory). Each is saved differently. */
- dialog = e_attachment_dialog_new (parent, attachment);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
+ source = e_attachment_get_file (attachment);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_return_if_fail (source != NULL || mime_part != NULL);
+
+ cancellable = e_file_activity_get_cancellable (file_activity);
+ progress_callback = e_file_activity_progress;
+
+ /* GFile is the easier, but probably less common case. The
+ * attachment already references an on-disk file, so we can
+ * just use GIO to copy it asynchronously.
+ *
+ * We use G_FILE_COPY_OVERWRITE because the user should have
+ * already confirmed the overwrite through the save dialog. */
+ if (G_IS_FILE (source))
+ g_file_copy_async (
+ source, destination,
+ G_FILE_COPY_OVERWRITE,
+ G_PRIORITY_DEFAULT, cancellable,
+ progress_callback, file_activity,
+ (GAsyncReadyCallback) attachment_save_file_cb,
+ g_object_ref (file_activity));
+
+ /* CamelMimePart can only be decoded to a file synchronously, so
+ * we do this in two stages. Stage one asynchronously opens the
+ * destination file for writing. Stage two spawns a thread that
+ * decodes the MIME part to the destination file. This stage is
+ * not cancellable, unfortunately. */
+ else if (CAMEL_IS_MIME_PART (mime_part)) {
+ g_object_set_data_full (
+ G_OBJECT (file_activity),
+ "attachment", g_object_ref (attachment),
+ (GDestroyNotify) g_object_unref);
+ g_file_replace_async (
+ destination, NULL, FALSE,
+ G_FILE_CREATE_REPLACE_DESTINATION,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_part_cb,
+ g_object_ref (file_activity));
+ }
}
-const gchar *
-e_attachment_get_description (EAttachment *attachment)
+#if 0
+typedef struct {
+ gint io_priority;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *simple;
+ GFileInfo *file_info;
+} BuildMimePartData;
+
+static BuildMimePartData *
+attachment_build_mime_part_data_new (EAttachment *attachment,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer source_tag)
{
- CamelMimePart *mime_part;
- const gchar *description;
+ BuildMimePartData *data;
+ GSimpleAsyncResult *simple;
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ simple = g_simple_async_result_new (
+ G_OBJECT (attachment), callback, user_data, source_tag);
- 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;
+ if (G_IS_CANCELLABLE (cancellable))
+ g_object_ref (cancellable);
- return description;
+ data = g_slice_new0 (BuildMimePartData);
+ data->io_priority = io_priority;
+ data->cancellable = cancellable;
+ data->simple = simple;
+ return data;
}
-void
-e_attachment_set_description (EAttachment *attachment,
- const gchar *description)
+static void
+attachment_build_mime_part_data_free (BuildMimePartData *data)
{
- CamelMimePart *mime_part;
+ if (data->attachment != NULL)
+ g_object_unref (data->attachment);
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
- g_free (attachment->priv->description);
- attachment->priv->description = g_strdup (description);
+ if (data->simple != NULL)
+ g_object_unref (data->simple);
- mime_part = e_attachment_get_mime_part (attachment);
- if (mime_part != NULL)
- camel_mime_part_set_description (mime_part, description);
+ if (data->file_info != NULL)
+ g_object_unref (data->file_info);
- g_object_notify (G_OBJECT (attachment), "description");
+ g_slice_free (BuildMimePartData, data);
}
-const gchar *
-e_attachment_get_disposition (EAttachment *attachment)
+static void
+attachment_build_mime_part_splice_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ GSimpleAsyncResult *final_result;
+ GCancellable *cancellable;
+ EAttachment *attachment;
+ CamelDataWrapper *wrapper;
CamelMimePart *mime_part;
- const gchar *disposition;
+ CamelStream *stream;
+ const gchar *content_type;
+ gchar *mime_type;
+ gssize length;
+ gpointer data;
+ GError *error = NULL;
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ final_result = G_SIMPLE_ASYNC_RESULT (user_data);
- mime_part = e_attachment_get_mime_part (attachment);
- if (mime_part != NULL)
- disposition = camel_mime_part_get_disposition (mime_part);
- else
- disposition = attachment->priv->disposition;
+ cancellable = g_cancellable_get_current ();
+ g_cancellable_pop_current (cancellable);
+ g_object_unref (cancellable);
- return disposition;
-}
+ length = g_output_stream_splice_finish (
+ G_OUTPUT_STREAM (source), result, &error);
+ if (error != NULL)
+ goto fail;
-void
-e_attachment_set_disposition (EAttachment *attachment,
- const gchar *disposition)
-{
- CamelMimePart *mime_part;
+ data = g_memory_output_stream_get_data (
+ G_MEMORY_OUTPUT_STREAM (source));
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ attachment = E_ATTACHMENT (
+ g_async_result_get_source_object (
+ G_ASYNC_RESULT (final_result)));
- g_free (attachment->priv->disposition);
- attachment->priv->disposition = g_strdup (disposition);
+ if (e_attachment_is_rfc822 (attachment))
+ wrapper = (CamelDataWrapper *) camel_mime_message_new ();
+ else
+ wrapper = camel_data_wrapper_new ();
- mime_part = e_attachment_get_mime_part (attachment);
- if (mime_part != NULL)
- camel_mime_part_set_disposition (mime_part, disposition);
+ content_type = e_attachment_get_content_type (attachment);
+ mime_type = g_content_type_get_mime_type (content_type);
- g_object_notify (G_OBJECT (attachment), "disposition");
-}
+ stream = camel_stream_mem_new_with_buffer (data, length);
+ camel_data_wrapper_construct_from_stream (wrapper, stream);
+ camel_data_wrapper_set_mime_type (wrapper, mime_type);
+ camel_object_unref (stream);
-const gchar *
-e_attachment_get_filename (EAttachment *attachment)
-{
- CamelMimePart *mime_part;
- const gchar *filename;
+ mime_part = camel_mime_part_new ();
+ camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ g_simple_async_result_set_op_res_gpointer (
+ final_result, mime_part, camel_object_unref);
- 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;
+ g_simple_async_result_complete (final_result);
+
+ camel_object_unref (wrapper);
+ g_free (mime_type);
+
+ return;
- return filename;
+fail:
+ g_simple_async_result_set_from_error (final_result, error);
+ g_simple_async_result_complete (final_result);
+ g_error_free (error);
}
-void
-e_attachment_set_filename (EAttachment *attachment,
- const gchar *filename)
+static void
+attachment_build_mime_part_read_cb (GObject *source,
+ GAsyncResult *result,
+ BuildMimePartData *data)
{
- CamelMimePart *mime_part;
+ GFileInputStream *input_stream;
+ GOutputStream *output_stream;
+ GCancellable *cancellable;
+ GError *error = NULL;
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ input_stream = g_file_read_finish (G_FILE (source), result, &error);
+ if (error != NULL)
+ goto fail;
- g_free (attachment->priv->filename);
- attachment->priv->filename = g_strdup (filename);
+ output_stream = g_memory_output_stream_new (
+ NULL, 0, g_realloc, g_free);
- mime_part = e_attachment_get_mime_part (attachment);
- if (mime_part != NULL)
- camel_mime_part_set_filename (mime_part, filename);
+ g_output_stream_splice_async (
+ output_stream, G_INPUT_STREAM (input_stream),
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT, cancellable,
+ attachment_build_mime_part_splice_cb, result);
- g_object_notify (G_OBJECT (attachment), "filename");
-}
+ g_cancellable_push_current (cancellable);
-CamelMimePart *
-e_attachment_get_mime_part (EAttachment *attachment)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ g_object_unref (input_stream);
+ g_object_unref (output_stream);
- return attachment->priv->mime_part;
+ return;
+
+fail:
+ g_simple_async_result_set_from_error (final_result, error);
+ g_simple_async_result_complete (final_result);
+ g_error_free (error);
}
-const gchar *
-e_attachment_get_mime_type (EAttachment *attachment)
+static gboolean
+attachment_build_mime_part_idle_cb (BuildMimePartData *data)
{
- CamelContentType *content_type;
- CamelMimePart *mime_part;
- const gchar *filename;
- gchar *mime_type;
+ GObject *source;
+ GAsyncResult *result;
+ GFileInfo *file_info;
+ GFile *file;
+ GError *error = NULL;
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
+ goto cancelled;
- if (attachment->priv->mime_type != NULL)
- goto exit;
+ result = G_ASYNC_RESULT (data->simple);
+ source = g_async_result_get_source_object (result);
+ file_info = e_attachment_get_file_info (E_ATTACHMENT (source));
- mime_part = e_attachment_get_mime_part (attachment);
- filename = e_attachment_get_filename (attachment);
- content_type = camel_mime_part_get_content_type (mime_part);
+ /* Poll again on the next idle. */
+ if (!G_IS_FILE_INFO (file_info))
+ return TRUE;
- 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);
- }
+ /* We have a GFileInfo, so on to step 2. */
- attachment->priv->mime_type = mime_type;
+ data->file_info = g_file_info_dup (file_info);
+ file = e_attachment_get_file (E_ATTACHMENT (source));
-exit:
- return attachment->priv->mime_type;
-}
+ /* Because Camel's stream API is synchronous and not
+ * cancellable, we have to asynchronously read the file
+ * into memory and then encode it to a MIME part. That
+ * means double buffering the file contents in memory,
+ * unfortunately. */
+ g_file_read_async (
+ file, data->io_priority, data->cancellable,
+ attachment_build_mime_part_read_cb, data);
-GdkPixbuf *
-e_attachment_get_thumbnail (EAttachment *attachment)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ return FALSE;
+
+cancelled:
+ g_simple_async_result_set_op_res_gboolean (data->simple, FALSE);
+ g_simple_async_result_set_from_error (data->simple, error);
+ g_simple_async_result_complete (data->simple);
- return attachment->priv->thumbnail;
+ build_mime_part_data_free (data);
+ g_error_free (error);
+
+ return FALSE;
}
void
-e_attachment_set_thumbnail (EAttachment *attachment,
- GdkPixbuf *thumbnail)
+e_attachment_build_mime_part_async (EAttachment *attachment,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ CamelMimePart *mime_part;
+ GSimpleAsyncResult *result;
+ GFile *file;
+
g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (callback != NULL);
- if (thumbnail != NULL) {
- g_return_if_fail (GDK_IS_PIXBUF (thumbnail));
- g_object_ref (thumbnail);
+ file = e_attachment_get_file (attachment);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_return_if_fail (file != NULL || mime_part != NULL);
+
+ result = g_simple_async_result_new (
+ G_OBJECT (attachment), callback, user_data,
+ e_attachment_build_mime_part_async);
+
+ /* First try the easy way out. */
+ if (CAMEL_IS_MIME_PART (mime_part)) {
+ camel_object_ref (mime_part);
+ g_simple_async_result_set_op_res_gpointer (
+ result, mime_part, camel_object_unref);
+ g_simple_async_result_complete_in_idle (result);
+ return;
}
- if (attachment->priv->thumbnail != NULL)
- g_object_unref (attachment->priv->thumbnail);
+ /* XXX g_cancellable_push_current() documentation lies.
+ * The function rejects NULL pointers, so create a
+ * dummy GCancellable if necessary. */
+ if (cancellable == NULL)
+ cancellable = g_cancellable_new ();
+ else
+ g_object_ref (cancellable);
- attachment->priv->thumbnail = thumbnail;
+ /* Because Camel's stream API is synchronous and not
+ * cancellable, we have to asynchronously read the file
+ * into memory and then encode it to a MIME part. That
+ * means it's double buffered, unfortunately. */
+ g_file_read_async (
+ file, G_PRIORITY_DEFAULT, cancellable,
+ attachment_build_mime_part_read_cb, result);
- g_object_notify (G_OBJECT (attachment), "thumbnail");
+ g_cancellable_push_current (cancellable);
}
-gboolean
-e_attachment_is_image (EAttachment *attachment)
+CamelMimePart *
+e_attachment_build_mime_part_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error)
{
- CamelContentType *content_type;
CamelMimePart *mime_part;
+ GSimpleAsyncResult *simple_result;
+ gboolean async_result_is_valid;
+ gpointer source_tag;
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- mime_part = e_attachment_get_mime_part (attachment);
- if (mime_part == NULL)
- return FALSE;
+ source_tag = e_attachment_build_mime_part_async;
+ async_result_is_valid = g_simple_async_result_is_valid (
+ result, G_OBJECT (attachment), source_tag);
+ g_return_val_if_fail (async_result_is_valid, NULL);
- content_type = camel_mime_part_get_content_type (mime_part);
+ simple_result = G_SIMPLE_ASYNC_RESULT (result);
+ g_simple_async_result_propagate_error (simple_result, error);
+ mime_part = g_simple_async_result_get_op_res_gpointer (simple_result);
+ attachment_file_info_to_mime_part (attachment, mime_part);
- return camel_content_type_is (content_type, "image", "*");
-}
+ if (CAMEL_IS_MIME_PART (mime_part))
+ camel_object_ref (mime_part);
-gboolean
-e_attachment_is_inline (EAttachment *attachment)
-{
- const gchar *disposition;
+ g_object_unref (result);
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ return mime_part;
+}
+#endif
- disposition = e_attachment_get_disposition (attachment);
- g_return_val_if_fail (disposition != NULL, FALSE);
+void
+_e_attachment_set_reference (EAttachment *attachment,
+ GtkTreeRowReference *reference)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (reference != NULL);
- return (g_ascii_strcasecmp (disposition, "inline") == 0);
+ gtk_tree_row_reference_free (attachment->priv->reference);
+ attachment->priv->reference = gtk_tree_row_reference_copy (reference);
}
diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h
index c69189c189..a7bb85dd75 100644
--- a/widgets/misc/e-attachment.h
+++ b/widgets/misc/e-attachment.h
@@ -1,4 +1,6 @@
/*
+ * e-attachment.h
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -13,10 +15,6 @@
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
@@ -25,11 +23,10 @@
#define E_ATTACHMENT_H
#include <gio/gio.h>
-#include <gtk/gtk.h>
-#include <glade/glade-xml.h>
#include <camel/camel-mime-part.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-cipher-context.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+#include <widgets/misc/e-file-activity.h>
/* Standard GObject macros */
#define E_TYPE_ATTACHMENT \
@@ -45,7 +42,7 @@
((obj), E_TYPE_ATTACHMENT))
#define E_IS_ATTACHMENT_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
- ((obj), E_TYPE_ATTACHMENT))
+ ((cls), E_TYPE_ATTACHMENT))
#define E_ATTACHMENT_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
@@ -58,63 +55,58 @@ typedef struct _EAttachmentPrivate EAttachmentPrivate;
struct _EAttachment {
GObject parent;
-
- gboolean guessed_type;
- gulong size;
-
- GCancellable *cancellable;
-
- gboolean is_available_local;
- int percentage;
- int index;
- char *store_uri;
-
- /* Status of signed/encrypted attachments */
- camel_cipher_validity_sign_t sign;
- camel_cipher_validity_encrypt_t encrypt;
-
EAttachmentPrivate *priv;
};
struct _EAttachmentClass {
GObjectClass parent_class;
-
- void (*changed) (EAttachment *attachment);
- void (*update) (EAttachment *attachment,
- gchar *message);
};
GType e_attachment_get_type (void);
-EAttachment * e_attachment_new (const gchar *filename,
- const gchar *disposition,
- CamelException *ex);
-EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
- const gchar *url,
- const gchar *disposition,
- const gchar *path,
- CamelException *ex);
-void e_attachment_build_remote_file (const gchar *filename,
- EAttachment *attachment,
- CamelException *ex);
-EAttachment * e_attachment_new_from_mime_part (CamelMimePart *part);
-void e_attachment_edit (EAttachment *attachment,
- GtkWindow *parent);
-const gchar * e_attachment_get_description (EAttachment *attachment);
-void e_attachment_set_description (EAttachment *attachment,
- const gchar *description);
+EAttachment * e_attachment_new (void);
+EAttachment * e_attachment_new_for_path (const gchar *path);
+EAttachment * e_attachment_new_for_uri (const gchar *uri);
+EAttachment * e_attachment_new_for_message (CamelMimeMessage *message);
+void e_attachment_add_to_multipart (EAttachment *attachment,
+ CamelMultipart *multipart,
+ const gchar *default_charset);
const gchar * e_attachment_get_disposition (EAttachment *attachment);
void e_attachment_set_disposition (EAttachment *attachment,
const gchar *disposition);
-const gchar * e_attachment_get_filename (EAttachment *attachment);
-void e_attachment_set_filename (EAttachment *attachment,
- const gchar *filename);
+GFile * e_attachment_get_file (EAttachment *attachment);
+void e_attachment_set_file (EAttachment *attachment,
+ GFile *file);
+GFileInfo * e_attachment_get_file_info (EAttachment *attachment);
CamelMimePart * e_attachment_get_mime_part (EAttachment *attachment);
-const gchar * e_attachment_get_mime_type (EAttachment *attachment);
-GdkPixbuf * e_attachment_get_thumbnail (EAttachment *attachment);
-void e_attachment_set_thumbnail (EAttachment *attachment,
- GdkPixbuf *pixbuf);
+void e_attachment_set_mime_part (EAttachment *attachment,
+ CamelMimePart *mime_part);
+const gchar * e_attachment_get_content_type (EAttachment *attachment);
+const gchar * e_attachment_get_display_name (EAttachment *attachment);
+const gchar * e_attachment_get_description (EAttachment *attachment);
+GIcon * e_attachment_get_icon (EAttachment *attachment);
+const gchar * e_attachment_get_thumbnail_path (EAttachment *attachment);
+guint64 e_attachment_get_size (EAttachment *attachment);
gboolean e_attachment_is_image (EAttachment *attachment);
-gboolean e_attachment_is_inline (EAttachment *attachment);
+gboolean e_attachment_is_rfc822 (EAttachment *attachment);
+void e_attachment_save_async (EAttachment *attachment,
+ EFileActivity *file_activity,
+ GFile *destination);
+
+#if 0
+void e_attachment_build_mime_part_async
+ (EAttachment *attachment,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+CamelMimePart * e_attachment_build_mime_part_finish
+ (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error);
+#endif
+
+/* For use by EAttachmentStore only. */
+void _e_attachment_set_reference (EAttachment *attachment,
+ GtkTreeRowReference *reference);
G_END_DECLS
diff --git a/widgets/misc/e-file-activity.c b/widgets/misc/e-file-activity.c
index 38dae234df..1957c20282 100644
--- a/widgets/misc/e-file-activity.c
+++ b/widgets/misc/e-file-activity.c
@@ -21,18 +21,25 @@
#include "e-file-activity.h"
+#include <stdarg.h>
+
#define E_FILE_ACTIVITY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_FILE_ACTIVITY, EFileActivityPrivate))
struct _EFileActivityPrivate {
GCancellable *cancellable;
+ GAsyncResult *result;
+ GFile *file;
+
gulong handler_id;
};
enum {
PROP_0,
- PROP_CANCELLABLE
+ PROP_CANCELLABLE,
+ PROP_FILE,
+ PROP_RESULT
};
static gpointer parent_class;
@@ -49,6 +56,18 @@ file_activity_set_property (GObject *object,
E_FILE_ACTIVITY (object),
g_value_get_object (value));
return;
+
+ case PROP_FILE:
+ e_file_activity_set_file (
+ E_FILE_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_RESULT:
+ e_file_activity_set_result (
+ E_FILE_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -66,6 +85,18 @@ file_activity_get_property (GObject *object,
value, e_file_activity_get_cancellable (
E_FILE_ACTIVITY (object)));
return;
+
+ case PROP_FILE:
+ g_value_set_object (
+ value, e_file_activity_get_file (
+ E_FILE_ACTIVITY (object)));
+ return;
+
+ case PROP_RESULT:
+ g_value_set_object (
+ value, e_file_activity_get_result (
+ E_FILE_ACTIVITY (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -85,6 +116,16 @@ file_activity_dispose (GObject *object)
priv->cancellable = NULL;
}
+ if (priv->result != NULL) {
+ g_object_unref (priv->result);
+ priv->result = NULL;
+ }
+
+ if (priv->file != NULL) {
+ g_object_unref (priv->file);
+ priv->file = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -129,6 +170,26 @@ file_activity_class_init (EFileActivityClass *class)
NULL,
G_TYPE_CANCELLABLE,
G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILE,
+ g_param_spec_object (
+ "file",
+ "File",
+ NULL,
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_RESULT,
+ g_param_spec_object (
+ "result",
+ "Result",
+ NULL,
+ G_TYPE_ASYNC_RESULT,
+ G_PARAM_READWRITE));
}
static void
@@ -179,6 +240,22 @@ e_file_activity_new (const gchar *primary_text)
"primary-text", primary_text, NULL);
}
+EActivity *
+e_file_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_file_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
GCancellable *
e_file_activity_get_cancellable (EFileActivity *file_activity)
{
@@ -218,6 +295,60 @@ e_file_activity_set_cancellable (EFileActivity *file_activity,
g_object_notify (G_OBJECT (file_activity), "cancellable");
}
+GFile *
+e_file_activity_get_file (EFileActivity *file_activity)
+{
+ g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+ return file_activity->priv->file;
+}
+
+void
+e_file_activity_set_file (EFileActivity *file_activity,
+ GFile *file)
+{
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ if (file != NULL) {
+ g_return_if_fail (G_IS_FILE (file));
+ g_object_ref (file);
+ }
+
+ if (file_activity->priv->file != NULL)
+ g_object_unref (file_activity->priv->file);
+
+ file_activity->priv->file = file;
+
+ g_object_notify (G_OBJECT (file_activity), "file");
+}
+
+GAsyncResult *
+e_file_activity_get_result (EFileActivity *file_activity)
+{
+ g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+ return file_activity->priv->result;
+}
+
+void
+e_file_activity_set_result (EFileActivity *file_activity,
+ GAsyncResult *result)
+{
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ if (result != NULL) {
+ g_return_if_fail (G_IS_ASYNC_RESULT (result));
+ g_object_ref (result);
+ }
+
+ if (file_activity->priv->result != NULL)
+ g_object_unref (file_activity->priv->result);
+
+ file_activity->priv->result = result;
+
+ g_object_notify (G_OBJECT (file_activity), "result");
+}
+
void
e_file_activity_progress (goffset current_num_bytes,
goffset total_num_bytes,
diff --git a/widgets/misc/e-file-activity.h b/widgets/misc/e-file-activity.h
index 4a57228872..acd144dec0 100644
--- a/widgets/misc/e-file-activity.h
+++ b/widgets/misc/e-file-activity.h
@@ -23,7 +23,7 @@
#define E_FILE_ACTIVITY_H
#include <gio/gio.h>
-#include <e-activity.h>
+#include <widgets/misc/e-activity.h>
/* Standard GObject macros */
#define E_TYPE_FILE_ACTIVITY \
@@ -61,9 +61,17 @@ struct _EFileActivityClass {
GType e_file_activity_get_type (void);
EActivity * e_file_activity_new (const gchar *primary_text);
+EActivity * e_file_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
GCancellable * e_file_activity_get_cancellable (EFileActivity *file_activity);
void e_file_activity_set_cancellable (EFileActivity *file_activity,
GCancellable *cancellable);
+GFile * e_file_activity_get_file (EFileActivity *file_activity);
+void e_file_activity_set_file (EFileActivity *file_activity,
+ GFile *file);
+GAsyncResult * e_file_activity_get_result (EFileActivity *file_activity);
+void e_file_activity_set_result (EFileActivity *file_activity,
+ GAsyncResult *result);
/* This can be used as a GFileProgressCallback. */
void e_file_activity_progress (goffset current_num_bytes,
diff --git a/widgets/misc/e-timeout-activity.c b/widgets/misc/e-timeout-activity.c
index d02bcf96d2..878d6b87a3 100644
--- a/widgets/misc/e-timeout-activity.c
+++ b/widgets/misc/e-timeout-activity.c
@@ -21,6 +21,8 @@
#include "e-timeout-activity.h"
+#include <stdarg.h>
+
#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
@@ -166,6 +168,22 @@ e_timeout_activity_new (const gchar *primary_text)
"primary-text", primary_text, NULL);
}
+EActivity *
+e_timeout_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_timeout_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
void
e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
guint seconds)
diff --git a/widgets/misc/e-timeout-activity.h b/widgets/misc/e-timeout-activity.h
index 70aaee7dcb..b395f39bde 100644
--- a/widgets/misc/e-timeout-activity.h
+++ b/widgets/misc/e-timeout-activity.h
@@ -63,6 +63,8 @@ struct _ETimeoutActivityClass {
GType e_timeout_activity_get_type (void);
EActivity * e_timeout_activity_new (const gchar *primary_text);
+EActivity * e_timeout_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
void e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
guint seconds);
diff --git a/widgets/table/Makefile.am b/widgets/table/Makefile.am
index 836a1dd570..c507770290 100644
--- a/widgets/table/Makefile.am
+++ b/widgets/table/Makefile.am
@@ -9,8 +9,9 @@ glade_DATA = \
e-table-field-chooser.glade
INCLUDES = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/widgets \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
+ $(E_UTIL_CFLAGS) \
$(E_WIDGETS_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
-DEVOLUTION_GLADEDIR=\"$(gladedir)\" \
@@ -147,6 +148,7 @@ libetable_la_LIBADD = \
$(WIN32_BOOTSTRAP_LIBS) \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/a11y/libevolution-a11y.la \
+ $(E_UTIL_LIBS) \
$(E_WIDGETS_LIBS) \
$(GNOME_PLATFORM_LIBS)
diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am
index df2b02c781..565ec4e521 100644
--- a/widgets/text/Makefile.am
+++ b/widgets/text/Makefile.am
@@ -5,6 +5,7 @@ endif
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/widgets \
+ $(E_UTIL_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
-DG_LOG_DOMAIN=\"e-text\"
@@ -30,5 +31,6 @@ libetext_la_LIBADD = \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/a11y/libevolution-a11y.la \
$(top_builddir)/widgets/table/libetable.la \
+ $(E_UTIL_LIBS) \
$(GNOME_PLATFORM_LIBS) \
$(REGEX_LIBS)