aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog62
-rw-r--r--mail/em-folder-tree.c266
-rw-r--r--mail/em-format.c3
-rw-r--r--mail/em-utils.c103
-rw-r--r--mail/em-utils.h5
-rw-r--r--mail/message-list.c277
6 files changed, 478 insertions, 238 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 9d9b74f4a9..ef85773d64 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,65 @@
+2004-05-17 Not Zed <NotZed@Ximian.com>
+
+ ** 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 <NotZed@Ximian.com>
+
+ ** 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.
+
2004-05-14 Jeffrey Stedfast <fejj@novell.com>
* em-popup.h: s/RESEND/EDIT/
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index bf814c1bb4..7248b363a9 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -597,7 +597,7 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model)
em_folder_tree_construct (emft, model);
g_object_ref (model);
- em_folder_tree_model_expand_foreach (model, emft_expand_node, emft);
+ em_folder_tree_model_expand_foreach (model, (EMFTModelExpandFunc)emft_expand_node, emft);
emft->priv->loading_row_id = g_signal_connect (model, "loading-row", G_CALLBACK (emft_maybe_expand_row), emft);
emft->priv->loaded_row_id = g_signal_connect (model, "loaded-row", G_CALLBACK (emft_maybe_expand_row), emft);
@@ -717,6 +717,7 @@ fail:
gtk_tree_path_free(src_path);
}
+/* TODO: Merge the drop handling code/menu's into one spot using a popup target for details */
/* Drop handling */
struct _DragDataReceivedAsync {
struct _mail_msg msg;
@@ -724,42 +725,20 @@ struct _DragDataReceivedAsync {
/* input data */
GdkDragContext *context;
- union {
- CamelStreamMem *rfc822;
- char *folder;
- char **urilist;
- struct {
- char *uri;
- GPtrArray *uids;
- } uidlist;
- } selection;
+ /* Only selection->data and selection->length are valid */
+ GtkSelectionData *selection;
CamelStore *store;
char *full_name;
- gboolean move;
+ guint32 action;
guint info;
- /* output data */
- gboolean moved;
+ unsigned int move:1;
+ unsigned int moved:1;
+ unsigned int aborted:1;
};
static void
-emft_drop_uid_list(struct _DragDataReceivedAsync *m, CamelFolder *dest)
-{
- CamelFolder *src;
-
- d(printf(" * drop uid list from '%s'\n", m->selection.uidlist.uri));
-
- if (!(src = mail_tool_uri_to_folder(m->selection.uidlist.uri, 0, &m->msg.ex)))
- return;
-
- camel_folder_transfer_messages_to(src, m->selection.uidlist.uids, dest, NULL, m->move, &m->msg.ex);
- camel_object_unref(src);
-
- m->moved = m->move && !camel_exception_is_set(&m->msg.ex);
-}
-
-static void
emft_drop_folder_rec (CamelStore *store, CamelFolderInfo *fi, const char *parent_name, CamelException *ex)
{
CamelFolder *src, *dest;
@@ -810,9 +789,9 @@ emft_drop_folder(struct _DragDataReceivedAsync *m)
CamelFolder *src;
char *new_name;
- d(printf(" * Drop folder '%s' onto '%s'\n", m->selection.folder, m->full_name));
+ d(printf(" * Drop folder '%s' onto '%s'\n", m->selection->data, m->full_name));
- if (!(src = mail_tool_uri_to_folder(m->selection.folder, 0, &m->msg.ex)))
+ if (!(src = mail_tool_uri_to_folder(m->selection->data, 0, &m->msg.ex)))
return;
/* handles dropping to the root properly */
@@ -846,83 +825,6 @@ emft_drop_folder(struct _DragDataReceivedAsync *m)
camel_object_unref(src);
}
-static gboolean
-emft_import_message_rfc822 (CamelFolder *dest, CamelStream *stream, gboolean scan_from, CamelException *ex)
-{
- CamelMimeParser *mp;
-
- mp = camel_mime_parser_new ();
- camel_mime_parser_scan_from (mp, scan_from);
- camel_mime_parser_init_with_stream (mp, stream);
-
- while (camel_mime_parser_step (mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) {
- CamelMessageInfo *info;
- CamelMimeMessage *msg;
-
- msg = camel_mime_message_new ();
- if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) {
- camel_object_unref (msg);
- camel_object_unref (mp);
- return FALSE;
- }
-
- /* append the message to the folder... */
- info = g_new0 (CamelMessageInfo, 1);
- camel_folder_append_message (dest, msg, info, NULL, ex);
- camel_object_unref (msg);
-
- if (camel_exception_is_set (ex)) {
- camel_object_unref (mp);
- return FALSE;
- }
-
- /* skip over the FROM_END state */
- camel_mime_parser_step (mp, 0, 0);
- }
-
- camel_object_unref (mp);
-
- return TRUE;
-}
-
-static void
-emft_drop_message_rfc822(struct _DragDataReceivedAsync *m, CamelFolder *dest)
-{
- gboolean scan_from;
-
- d(printf(" * drop message/rfc822\n"));
-
- scan_from = m->selection.rfc822->buffer->len > 5
- && !strncmp(m->selection.rfc822->buffer->data, "From ", 5);
- emft_import_message_rfc822(dest, (CamelStream *)m->selection.rfc822, scan_from, &m->msg.ex);
-}
-
-static void
-emft_drop_text_uri_list(struct _DragDataReceivedAsync *m, CamelFolder *dest)
-{
- CamelStream *stream;
- CamelURL *url;
- int fd, i, go=1;
-
- d(printf(" * drop uri list\n"));
-
- for (i = 0; go && m->selection.urilist[i] != NULL; i++) {
- d(printf(" - '%s'\n", (char *)m->selection.urilist[i]));
-
- url = camel_url_new(m->selection.urilist[i], NULL);
- if (url == NULL)
- continue;
-
- if (strcmp(url->protocol, "file") == 0
- && (fd = open(url->path, O_RDONLY)) != -1) {
- stream = camel_stream_fs_new_with_fd(fd);
- go = emft_import_message_rfc822(dest, stream, TRUE, &m->msg.ex);
- camel_object_unref(stream);
- }
- camel_url_free(url);
- }
-}
-
static char *
emft_drop_async_desc (struct _mail_msg *mm, int done)
{
@@ -931,7 +833,7 @@ emft_drop_async_desc (struct _mail_msg *mm, int done)
char *buf;
if (m->info == DND_DROP_TYPE_FOLDER) {
- url = camel_url_new (m->selection.folder, NULL);
+ url = camel_url_new (m->selection->data, NULL);
if (m->move)
buf = g_strdup_printf (_("Moving folder %s"), url->fragment ? url->fragment : url->path + 1);
@@ -966,15 +868,16 @@ emft_drop_async_drop (struct _mail_msg *mm)
switch (m->info) {
case DND_DROP_TYPE_UID_LIST:
/* import a list of uids from another evo folder */
- emft_drop_uid_list(m, folder);
+ em_utils_selection_get_uidlist(m->selection, folder, m->move, &mm->ex);
+ m->moved = m->move && !camel_exception_is_set(&mm->ex);
break;
case DND_DROP_TYPE_MESSAGE_RFC822:
/* import a message/rfc822 stream */
- emft_drop_message_rfc822(m, folder);
+ em_utils_selection_get_message(m->selection, folder);
break;
case DND_DROP_TYPE_TEXT_URI_LIST:
/* import an mbox, maildir, or mh folder? */
- emft_drop_text_uri_list(m, folder);
+ em_utils_selection_get_mailbox(m->selection, folder);
break;
default:
abort();
@@ -989,8 +892,14 @@ emft_drop_async_done (struct _mail_msg *mm)
struct _DragDataReceivedAsync *m = (struct _DragDataReceivedAsync *) mm;
gboolean success, delete;
- success = !camel_exception_is_set (&mm->ex);
- delete = success && m->move && !m->moved;
+ /* ?? */
+ 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);
}
@@ -1004,23 +913,8 @@ emft_drop_async_free (struct _mail_msg *mm)
camel_object_unref(m->store);
g_free(m->full_name);
- switch (m->info) {
- case DND_DROP_TYPE_FOLDER:
- g_free(m->selection.folder);
- break;
- case DND_DROP_TYPE_UID_LIST:
- g_free(m->selection.uidlist.uri);
- em_utils_uids_free(m->selection.uidlist.uids);
- break;
- case DND_DROP_TYPE_MESSAGE_RFC822:
- camel_object_unref(m->selection.rfc822);
- break;
- case DND_DROP_TYPE_TEXT_URI_LIST:
- g_strfreev(m->selection.urilist);
- break;
- default:
- abort();
- }
+ g_free(m->selection->data);
+ g_free(m->selection);
}
static struct _mail_msg_op emft_drop_async_op = {
@@ -1031,6 +925,43 @@ static struct _mail_msg_op emft_drop_async_op = {
};
static void
+tree_drag_data_action(struct _DragDataReceivedAsync *m)
+{
+ m->move = m->action == GDK_ACTION_MOVE;
+ e_thread_put (mail_thread_new, (EMsg *) m);
+}
+
+static void
+emft_drop_popup_copy(GtkWidget *item, struct _DragDataReceivedAsync *m)
+{
+ m->action = GDK_ACTION_COPY;
+ tree_drag_data_action(m);
+}
+
+static void
+emft_drop_popup_move(GtkWidget *item, struct _DragDataReceivedAsync *m)
+{
+ m->action = GDK_ACTION_MOVE;
+ tree_drag_data_action(m);
+}
+
+static void
+emft_drop_popup_cancel(GtkWidget *item, struct _DragDataReceivedAsync *m)
+{
+ m->aborted = TRUE;
+ mail_msg_free(&m->msg);
+}
+
+static EMPopupItem emft_drop_popup_menu[] = {
+ { EM_POPUP_ITEM, "00.emc.00", N_("_Copy to Folder"), G_CALLBACK (emft_drop_popup_copy), NULL, NULL, 1 },
+ { EM_POPUP_ITEM, "00.emc.01", N_("_Move to Folder"), G_CALLBACK (emft_drop_popup_move), NULL, NULL, 1 },
+ { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK (emft_drop_popup_copy), NULL, "stock_folder-copy", 2 },
+ { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK (emft_drop_popup_move), NULL, "stock_folder-move", 2 },
+ { EM_POPUP_BAR, "10.emc" },
+ { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK (emft_drop_popup_cancel), NULL, "stock_cancel", 0 },
+};
+
+static void
tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection, guint info, guint time, EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv = emft->priv;
@@ -1040,8 +971,10 @@ tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y
const char *full_name;
CamelStore *store;
GtkTreeIter iter;
- char *path, *tmp;
+ char *path;
int i;
+
+ printf("drag data received, action %d\n", context->action);
if (!gtk_tree_view_get_dest_row_at_pos (priv->treeview, x, y, &dest_path, &pos))
return;
@@ -1075,31 +1008,41 @@ tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y
m->store = store;
camel_object_ref(store);
m->full_name = g_strdup (full_name);
- m->move = context->action == GDK_ACTION_MOVE;
+ m->action = context->action;
m->info = info;
- switch (info) {
- case DND_DROP_TYPE_FOLDER:
- m->selection.folder = g_strdup(selection->data);
- break;
- case DND_DROP_TYPE_UID_LIST:
- em_utils_selection_get_uidlist(selection, &m->selection.uidlist.uri, &m->selection.uidlist.uids);
- break;
- case DND_DROP_TYPE_MESSAGE_RFC822:
- m->selection.rfc822 = (CamelStreamMem *)camel_stream_mem_new_with_buffer(selection->data, selection->length);
- break;
- case DND_DROP_TYPE_TEXT_URI_LIST:
- tmp = g_strndup(selection->data, selection->length);
- m->selection.urilist = g_strsplit(tmp, "\n", 0);
- g_free(tmp);
- for (i=0;m->selection.urilist[i];i++)
- g_strstrip(m->selection.urilist[i]);
- break;
- default:
- abort();
+ /* need to copy, goes away once we exit */
+ 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;
+
+ if (context->action == GDK_ACTION_ASK) {
+ EMPopup *emp;
+ int mask;
+ GSList *menus = NULL;
+ GtkMenu *menu;
+
+ emp = em_popup_new("com.ximian.mail.storageset.popup.drop");
+ if (info != DND_DROP_TYPE_FOLDER)
+ mask = ~1;
+ else
+ mask = ~2;
+
+ for (i=0;i<sizeof(emft_drop_popup_menu)/sizeof(emft_drop_popup_menu[0]);i++) {
+ EMPopupItem *item = &emft_drop_popup_menu[i];
+
+ if ((item->mask & mask) == 0) {
+ item->activate_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, mask, mask);
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
+ } else {
+ tree_drag_data_action(m);
}
-
- e_thread_put (mail_thread_new, (EMsg *) m);
}
static gboolean
@@ -1448,21 +1391,16 @@ tree_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, guin
g_source_remove (priv->autoexpand_id);
priv->autoexpand_id = 0;
}
-
+
target = emft_drop_target(emft, context, path);
if (target != GDK_NONE) {
for (i=0; i<NUM_DROP_TYPES; i++) {
if (drop_atoms[i] == target) {
switch (i) {
- case DND_DROP_TYPE_FOLDER:
- action = context->suggested_action;
- if (context->actions & GDK_ACTION_MOVE)
- action = GDK_ACTION_MOVE;
- gtk_tree_view_set_drag_dest_row(priv->treeview, path, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
- break;
case DND_DROP_TYPE_UID_LIST:
+ case DND_DROP_TYPE_FOLDER:
action = context->suggested_action;
- if (context->actions & GDK_ACTION_MOVE)
+ if (action == GDK_ACTION_COPY && (context->actions & GDK_ACTION_MOVE))
action = GDK_ACTION_MOVE;
gtk_tree_view_set_drag_dest_row(priv->treeview, path, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
break;
@@ -1503,8 +1441,8 @@ em_folder_tree_enable_drag_and_drop (EMFolderTree *emft)
setup = 1;
}
- gtk_drag_source_set((GtkWidget *)priv->treeview, GDK_BUTTON1_MASK, drag_types, NUM_DRAG_TYPES, GDK_ACTION_COPY | GDK_ACTION_MOVE);
- gtk_drag_dest_set((GtkWidget *)priv->treeview, GTK_DEST_DEFAULT_ALL, drop_types, NUM_DROP_TYPES, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ gtk_drag_source_set((GtkWidget *)priv->treeview, GDK_BUTTON1_MASK, drag_types, NUM_DRAG_TYPES, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+ gtk_drag_dest_set((GtkWidget *)priv->treeview, GTK_DEST_DEFAULT_ALL, drop_types, NUM_DROP_TYPES, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
g_signal_connect (priv->treeview, "drag-begin", G_CALLBACK (tree_drag_begin), emft);
g_signal_connect (priv->treeview, "drag-data-delete", G_CALLBACK (tree_drag_data_delete), emft);
diff --git a/mail/em-format.c b/mail/em-format.c
index a93b63728c..2ba834b9d6 100644
--- a/mail/em-format.c
+++ b/mail/em-format.c
@@ -747,7 +747,6 @@ static const struct {
{ N_("Subject"), EM_FORMAT_HEADER_BOLD },
{ N_("Date"), EM_FORMAT_HEADER_BOLD },
{ N_("Newsgroups"), EM_FORMAT_HEADER_BOLD },
- { "x-evolution-mailer", 0 }, /* DO NOT translate */
};
/**
@@ -764,7 +763,7 @@ em_format_default_headers(EMFormat *emf)
int i;
em_format_clear_headers(emf);
- for (i = 0; i < G_N_ELEMENTS (default_headers) - 1; i++)
+ for (i=0; i<sizeof(default_headers)/sizeof(default_headers[0]); i++)
em_format_add_header(emf, default_headers[i].name, default_headers[i].flags);
}
diff --git a/mail/em-utils.c b/mail/em-utils.c
index ca082a8423..e655b456c1 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -793,7 +793,6 @@ em_utils_read_messages_from_stream(CamelFolder *folder, CamelStream *stream)
camel_mime_parser_scan_from(mp, TRUE);
camel_mime_parser_init_with_stream(mp, stream);
- camel_object_unref(stream);
while (camel_mime_parser_step(mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) {
CamelMimeMessage *msg;
@@ -872,6 +871,33 @@ em_utils_selection_get_mailbox(GtkSelectionData *data, CamelFolder *folder)
}
/**
+ * em_utils_selection_get_message:
+ * @data:
+ * @folder:
+ *
+ * get a message/rfc822 data.
+ **/
+void
+em_utils_selection_get_message(GtkSelectionData *data, CamelFolder *folder)
+{
+ CamelStream *stream;
+ CamelException *ex;
+ CamelMimeMessage *msg;
+
+ if (data->data == NULL || data->length == -1)
+ return;
+
+ ex = camel_exception_new();
+ stream = camel_stream_mem_new_with_buffer(data->data, data->length);
+ msg = camel_mime_message_new();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) == 0)
+ camel_folder_append_message(folder, msg, NULL, NULL, ex);
+ camel_object_unref(msg);
+ camel_object_unref(stream);
+ camel_exception_free(ex);
+}
+
+/**
* em_utils_selection_set_uidlist:
* @data: selection data
* @uri:
@@ -901,27 +927,22 @@ em_utils_selection_set_uidlist(GtkSelectionData *data, const char *uri, GPtrArra
/**
* em_utils_selection_get_uidlist:
* @data: selection data
- * @urip: Pointer to uri string, to be free'd by caller
- * @uidsp: Pointer to an array of uid's.
+ * @move: do we delete the messages.
*
- * Convert an x-uid-list type to a uri and a uid list.
+ * Convert a uid list into a copy/move operation.
*
- * Return value: The number of uid's found. If 0, then @urip and
- * @uidsp will be empty.
+ * Warning: Could take some time to run.
**/
-int
-em_utils_selection_get_uidlist(GtkSelectionData *data, char **urip, GPtrArray **uidsp)
+void
+em_utils_selection_get_uidlist(GtkSelectionData *data, CamelFolder *dest, int move, CamelException *ex)
{
/* format: "uri\0uid1\0uid2\0uid3\0...\0uidn" */
char *inptr, *inend;
GPtrArray *uids;
- int res;
-
- *urip = NULL;
- *uidsp = NULL;
+ CamelFolder *folder;
if (data == NULL || data->data == NULL || data->length == -1)
- return 0;
+ return;
uids = g_ptr_array_new();
@@ -941,14 +962,16 @@ em_utils_selection_get_uidlist(GtkSelectionData *data, char **urip, GPtrArray **
if (uids->len == 0) {
g_ptr_array_free(uids, TRUE);
- res = 0;
- } else {
- *urip = g_strdup(data->data);
- *uidsp = uids;
- res = uids->len;
+ return;
}
- return res;
+ folder = mail_tool_uri_to_folder(data->data, 0, ex);
+ if (folder) {
+ camel_folder_transfer_messages_to(folder, uids, dest, NULL, move, ex);
+ camel_object_unref(folder);
+ }
+
+ em_utils_uids_free(uids);
}
/**
@@ -1011,6 +1034,48 @@ em_utils_selection_set_urilist(GtkSelectionData *data, CamelFolder *folder, GPtr
}
}
+/**
+ * em_utils_selection_set_urilist:
+ * @data:
+ * @folder:
+ * @uids:
+ *
+ * Get the selection data @data from a uri list which points to a
+ * file, which is a berkely mailbox format mailbox. The file is
+ * automatically cleaned up when the application quits.
+ **/
+void
+em_utils_selection_get_urilist(GtkSelectionData *data, CamelFolder *folder)
+{
+ CamelStream *stream;
+ CamelURL *url;
+ int fd, i, res = 0;
+ char *tmp, **uris;
+
+ d(printf(" * drop uri list\n"));
+
+ tmp = g_strndup(data->data, data->length);
+ uris = g_strsplit(tmp, "\n", 0);
+ g_free(tmp);
+ for (i=0;res == 0 && uris[i];i++) {
+ g_strstrip(uris[i]);
+
+ url = camel_url_new(uris[i], NULL);
+ if (url == NULL)
+ continue;
+
+ if (strcmp(url->protocol, "file") == 0
+ && (fd = open(url->path, O_RDONLY)) != -1) {
+ stream = camel_stream_fs_new_with_fd(fd);
+ res = em_utils_read_messages_from_stream(folder, stream);
+ camel_object_unref(stream);
+ }
+ camel_url_free(url);
+ }
+
+ g_strfreev(uris);
+}
+
static void
emu_save_part_done(CamelMimePart *part, char *name, int done, void *data)
{
diff --git a/mail/em-utils.h b/mail/em-utils.h
index 368265ba69..4e433ab12d 100644
--- a/mail/em-utils.h
+++ b/mail/em-utils.h
@@ -39,6 +39,7 @@ struct _CamelMimeMessage;
struct _CamelMimePart;
struct _GtkSelectionData;
struct _GtkAdjustment;
+struct _CamelException;
gboolean em_utils_prompt_user(struct _GtkWindow *parent, const char *promptkey, const char *tag, const char *arg0, ...);
@@ -65,10 +66,12 @@ void em_utils_flag_for_followup_completed (struct _GtkWidget *parent, struct _Ca
void em_utils_selection_set_mailbox(struct _GtkSelectionData *data, struct _CamelFolder *folder, GPtrArray *uids);
void em_utils_selection_get_mailbox(struct _GtkSelectionData *data, struct _CamelFolder *folder);
+void em_utils_selection_get_message(struct _GtkSelectionData *data, struct _CamelFolder *folder);
/* FIXME: be nice if these also worked on struct _CamelFolder's, no easy way to get uri from folder yet tho */
void em_utils_selection_set_uidlist(struct _GtkSelectionData *data, const char *uri, GPtrArray *uids);
-int em_utils_selection_get_uidlist(struct _GtkSelectionData *data, char **uri, GPtrArray **uidsp);
+void em_utils_selection_get_uidlist(struct _GtkSelectionData *data, struct _CamelFolder *dest, int move, struct _CamelException *ex);
void em_utils_selection_set_urilist(struct _GtkSelectionData *data, struct _CamelFolder *folder, GPtrArray *uids);
+void em_utils_selection_get_urilist(struct _GtkSelectionData *data, struct _CamelFolder *folder);
char *em_utils_temp_save_part(struct _GtkWidget *parent, struct _CamelMimePart *part);
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 <e-util/e-icon-factory.h>
@@ -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
*
@@ -1462,29 +1492,6 @@ ml_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, MessageLis
}
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)
{
if (data->target != gdk_atom_intern ("x-uid-list", FALSE)) {
@@ -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;i<sizeof(ml_drop_popup_menu)/sizeof(ml_drop_popup_menu[0]);i++) {
+ EMPopupItem *item = &ml_drop_popup_menu[i];
+
+ item->activate_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;i<sizeof(ml_drag_info)/sizeof(ml_drag_info[0]);i++)
+ if (targets->data == (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;i<sizeof(ml_drag_info)/sizeof(ml_drag_info[0]);i++)
+ ml_drag_info[i].atom = gdk_atom_intern(ml_drag_info[i].target, FALSE);
+
object_class->finalize = 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);
}
/**