From 81f6e6db484ce6978d9e69be9ee43200f612ef97 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Mon, 17 May 2004 03:50:56 +0000 Subject: ** Bug #6556. 2004-05-17 Not Zed ** Bug #6556. * message-list.c (ml_drop_async_desc, ml_drop_async_drop) (ml_drop_async_done, ml_drop_async_free, ml_drag_data_action) (ml_drop_popup_copy, ml_drop_popup_move, ml_drop_popup_cancel) (ml_tree_drag_data_received): implement async drop operations and the ask drop option menu. 2004-05-14 Not Zed ** Bug #6556. * message-list.c (ml_selection_received_uidlist): removed, not needed anymore. (ml_selection_received): call get_uidlist to paste the selection. (ml_tree_drag_data_received): same here. * em-folder-tree.c (emft_drop_uid_list): removed, not needed because of below change. * em-utils.c (em_utils_selection_get_uidlist): actually do the copy now, don't just decode the data. * em-folder-tree.c (tree_drag_data_received): just copy the selection data data itself, dont decode yet. (emft_import_message_rfc822): removed, not needed, use em utils stuff instead. (emft_drop_message_rfc822): same. (emft_drop_text_uri_list): same. (emft_drop_async_free): simply free stuff. (emft_drop_async_drop): call em_utils stuff where they exist to do the drop. * message-list.c (ml_tree_drag_data_get): send x-mailbox instead of message/rfc822 for the mailbox. (ml_tree_drag_data_received): handle drop of x-mailbox differently to message/rfc822. (ml_tree_drag_motion): implement so proper options are setup whilst dragging. (message_list_construct): seutp the drag src/dest types for changes typs and with ASK action. * em-utils.c (em_utils_read_messages_from_stream): dont unref the stream when we get it. (em_utils_selection_get_mailbox): add an argument to scan from or not, for message/rfc822 vs x-mailbox drops. (em_utils_read_messages_from_stream): Same. * em-folder-tree.c (tree_drag_motion): default to move properly. * message-list.c (ml_selection_received_uidlist): take a move flag. (ml_tree_drag_data_received): handle move action. * em-folder-tree.c (em_folder_tree_new_with_model): got sick of this bloody warning. * em-format.c (default_headers[]): just remove x-mailer from the header list, if it isn't on by default. This is the default list. (em_format_default_headers): loop through everything. svn path=/trunk/; revision=25915 --- mail/message-list.c | 277 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 225 insertions(+), 52 deletions(-) (limited to 'mail/message-list.c') diff --git a/mail/message-list.c b/mail/message-list.c index 252957445e..0fd105c14e 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -65,6 +65,7 @@ #include "mail-mt.h" #include "mail-tools.h" #include "mail-ops.h" +#include "em-popup.h" #include "em-utils.h" #include @@ -91,6 +92,35 @@ struct _MessageListPrivate { struct _MLSelection clipboard; }; +static struct { + char *target; + GdkAtom atom; + guint32 actions; +} ml_drag_info[] = { + { "x-uid-list", 0, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY }, + { "message/rfc822", 0, GDK_ACTION_COPY }, + { "text/uri-list", 0, GDK_ACTION_COPY }, +}; + +enum { + DND_X_UID_LIST, /* x-uid-list */ + DND_MESSAGE_RFC822, /* message/rfc822 */ + DND_TEXT_URI_LIST /* text/uri-list */ +}; + +/* What we send */ +static GtkTargetEntry ml_drag_types[] = { + { "x-uid-list", 0, DND_X_UID_LIST }, + { "text/uri-list", 0, DND_TEXT_URI_LIST }, +}; + +/* What we accept */ +static GtkTargetEntry ml_drop_types[] = { + { "x-uid-list", 0, DND_X_UID_LIST }, + { "message/rfc822", 0, DND_MESSAGE_RFC822 }, + { "text/uri-list", 0, DND_TEXT_URI_LIST }, +}; + /* * Default sizes for the ETable display * @@ -1461,29 +1491,6 @@ ml_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, MessageLis return TRUE; } -static void -ml_selection_received_uidlist(MessageList *ml, GtkSelectionData *data) -{ - CamelFolder *folder; - GPtrArray *uids; - char *uri; - - if (em_utils_selection_get_uidlist(data, &uri, &uids) == 0) - return; - - folder = mail_tool_uri_to_folder(uri, 0, NULL); - if (folder) { - mail_transfer_messages(folder, uids, FALSE, ml->folder_uri, 0, NULL, NULL); - camel_object_unref(folder); - } else { - /* FIXME: error box? */ - g_warning("could not open paste source uri '%s'", uri); - em_utils_uids_free(uids); - } - - g_free(uri); -} - static void ml_selection_received(GtkWidget *widget, GtkSelectionData *data, guint time, MessageList *ml) { @@ -1493,16 +1500,9 @@ ml_selection_received(GtkWidget *widget, GtkSelectionData *data, guint time, Mes return; } - ml_selection_received_uidlist(ml, data); + em_utils_selection_get_uidlist(data, ml->folder, FALSE, NULL); } -static GtkTargetEntry ml_drag_types[] = { - { "x-uid-list", 0, 0 }, - { "message/rfc822", 0, 1 }, - /* not included in dest types */ - { "text/uri-list", 0, 2 }, -}; - static void ml_tree_drag_data_get (ETree *tree, int row, ETreePath path, int col, GdkDragContext *context, GtkSelectionData *data, @@ -1514,13 +1514,10 @@ ml_tree_drag_data_get (ETree *tree, int row, ETreePath path, int col, if (uids->len > 0) { switch (info) { - case 0 /* DND_TARGET_TYPE_X_UID_LIST */: + case DND_X_UID_LIST: em_utils_selection_set_uidlist(data, ml->folder_uri, uids); break; - case 1 /* DND_TARGET_TYPE_MESSAGE_RFC822 */: - em_utils_selection_set_mailbox(data, ml->folder, uids); - break; - case 2 /* DND_TARGET_TYPE_TEXT_URI_LIST */: + case DND_TEXT_URI_LIST: em_utils_selection_set_urilist(data, ml->folder, uids); break; } @@ -1529,29 +1526,200 @@ ml_tree_drag_data_get (ETree *tree, int row, ETreePath path, int col, message_list_free_uids(ml, uids); } +/* TODO: merge this with the folder tree stuff via empopup targets */ +/* Drop handling */ +struct _drop_msg { + struct _mail_msg msg; + + GdkDragContext *context; + + /* Only selection->data and selection->length are valid */ + GtkSelectionData *selection; + + CamelFolder *folder; + + guint32 action; + guint info; + + unsigned int move:1; + unsigned int moved:1; + unsigned int aborted:1; +}; + +static char * +ml_drop_async_desc (struct _mail_msg *mm, int done) +{ + struct _drop_msg *m = (struct _drop_msg *) mm; + + if (m->move) + return g_strdup_printf(_("Moving messages into folder %s"), m->folder->full_name); + else + return g_strdup_printf(_("Copying messages into folder %s"), m->folder->full_name); +} + +static void +ml_drop_async_drop(struct _mail_msg *mm) +{ + struct _drop_msg *m = (struct _drop_msg *)mm; + + switch (m->info) { + case DND_X_UID_LIST: + em_utils_selection_get_uidlist(m->selection, m->folder, m->action == GDK_ACTION_MOVE, &mm->ex); + break; + case DND_MESSAGE_RFC822: + em_utils_selection_get_message(m->selection, m->folder); + break; + case DND_TEXT_URI_LIST: + em_utils_selection_get_urilist(m->selection, m->folder); + break; + } +} + +static void +ml_drop_async_done(struct _mail_msg *mm) +{ + struct _drop_msg *m = (struct _drop_msg *)mm; + gboolean success, delete; + + /* ?? */ + if (m->aborted) { + success = FALSE; + delete = FALSE; + } else { + success = !camel_exception_is_set (&mm->ex); + delete = success && m->move && !m->moved; + } + + gtk_drag_finish(m->context, success, delete, GDK_CURRENT_TIME); +} + +static void +ml_drop_async_free(struct _mail_msg *mm) +{ + struct _drop_msg *m = (struct _drop_msg *)mm; + + g_object_unref(m->context); + camel_object_unref(m->folder); + + g_free(m->selection->data); + g_free(m->selection); +} + +static struct _mail_msg_op ml_drop_async_op = { + ml_drop_async_desc, + ml_drop_async_drop, + ml_drop_async_done, + ml_drop_async_free, +}; + +static void +ml_drop_action(struct _drop_msg *m) +{ + m->move = m->action == GDK_ACTION_MOVE; + e_thread_put (mail_thread_new, (EMsg *) m); +} + +static void +ml_drop_popup_copy(GtkWidget *item, struct _drop_msg *m) +{ + m->action = GDK_ACTION_COPY; + ml_drop_action(m); +} + +static void +ml_drop_popup_move(GtkWidget *item, struct _drop_msg *m) +{ + m->action = GDK_ACTION_MOVE; + ml_drop_action(m); +} + +static void +ml_drop_popup_cancel(GtkWidget *item, struct _drop_msg *m) +{ + m->aborted = TRUE; + mail_msg_free(&m->msg); +} + +static EMPopupItem ml_drop_popup_menu[] = { + { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK(ml_drop_popup_copy), NULL, "stock_folder-copy", 0 }, + { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK(ml_drop_popup_move), NULL, "stock_folder-move", 0 }, + { EM_POPUP_BAR, "10.emc" }, + { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK(ml_drop_popup_cancel), NULL, NULL, 0 }, +}; + static void ml_tree_drag_data_received (ETree *tree, int row, ETreePath path, int col, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, MessageList *ml) { + struct _drop_msg *m; + /* this means we are receiving no data */ if (data->data == NULL || data->length == -1) return; - /* Note: we don't receive text/uri-list, since we have no - guarantee on what the content would be */ - - switch (info) { - case 1 /* DND_TARGET_TYPE_MESSAGE_RFC822 */: - em_utils_selection_get_mailbox(data, ml->folder); - break; - case 0 /* DND_TARGET_TYPE_X_UID_LIST */: - ml_selection_received_uidlist(ml, data); - break; + m = mail_msg_new(&ml_drop_async_op, NULL, sizeof(*m)); + m->context = context; + g_object_ref(context); + m->folder = ml->folder; + camel_object_ref(m->folder); + m->action = context->action; + m->info = info; + + /* need to copy, goes away once we exit */ + m->selection = g_malloc0(sizeof(*m->selection)); + m->selection->data = g_malloc(data->length); + memcpy(m->selection->data, data->data, data->length); + m->selection->length = data->length; + + if (context->action == GDK_ACTION_ASK) { + EMPopup *emp; + GSList *menus = NULL; + GtkMenu *menu; + int i; + + emp = em_popup_new("com.ximian.mail.messagelist.popup.drop"); + for (i=0;iactivate_data = m; + menus = g_slist_append(menus, item); + } + em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); + menu = em_popup_create_menu_once(emp, NULL, 0, 0); + gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); + } else { + ml_drop_action(m); } - - gtk_drag_finish(context, TRUE, TRUE, time); +} + +static gboolean +ml_tree_drag_motion(ETree *tree, GdkDragContext *context, gint x, gint y, guint time, MessageList *ml) +{ + GList *targets; + GdkDragAction action, actions = 0; + + for (targets = context->targets; targets; targets = targets->next) { + int i; + + printf("atom drop '%s'\n", gdk_atom_name(targets->data)); + for (i=0;idata == (void *)ml_drag_info[i].atom) + actions |= ml_drag_info[i].actions; + } + printf("\n"); + + actions &= context->actions; + action = context->suggested_action; + if (action == GDK_ACTION_COPY && (actions & GDK_ACTION_MOVE)) + action = GDK_ACTION_MOVE; + else if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY)) + action = GDK_ACTION_MOVE; + + gdk_drag_status(context, action, time); + + return action != 0; } static void @@ -1709,8 +1877,13 @@ message_list_finalise (GObject *object) static void message_list_class_init (GObjectClass *object_class) { + int i; + message_list_parent_class = g_type_class_ref(PARENT_TYPE); + for (i=0;ifinalize = message_list_finalise; ((GtkObjectClass *)object_class)->destroy = message_list_destroy; @@ -1804,18 +1977,18 @@ message_list_construct (MessageList *message_list) e_tree_drag_source_set(message_list->tree, GDK_BUTTON1_MASK, ml_drag_types, sizeof(ml_drag_types)/sizeof(ml_drag_types[0]), - GDK_ACTION_MOVE|GDK_ACTION_COPY); + GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_ASK); g_signal_connect(message_list->tree, "tree_drag_data_get", G_CALLBACK(ml_tree_drag_data_get), message_list); - /* note, we only include 2 types, we don't include text/uri-list as a receiver */ e_tree_drag_dest_set(message_list->tree, GTK_DEST_DEFAULT_ALL, - ml_drag_types, 2, - GDK_ACTION_MOVE|GDK_ACTION_COPY); + ml_drop_types, sizeof(ml_drop_types)/sizeof(ml_drop_types[0]), + GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_ASK); g_signal_connect(message_list->tree, "tree_drag_data_received", G_CALLBACK(ml_tree_drag_data_received), message_list); + g_signal_connect(message_list->tree, "drag-motion", G_CALLBACK(ml_tree_drag_motion), message_list); } /** -- cgit v1.2.3