aboutsummaryrefslogtreecommitdiffstats
path: root/mail/em-folder-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/em-folder-tree.c')
-rw-r--r--mail/em-folder-tree.c266
1 files changed, 102 insertions, 164 deletions
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);