diff options
Diffstat (limited to 'mail')
-rw-r--r-- | mail/ChangeLog | 35 | ||||
-rw-r--r-- | mail/em-folder-tree-model.c | 471 | ||||
-rw-r--r-- | mail/em-folder-tree-model.h | 15 | ||||
-rw-r--r-- | mail/em-folder-tree.c | 462 | ||||
-rw-r--r-- | mail/em-folder-tree.h | 2 | ||||
-rw-r--r-- | mail/em-marshal.list | 1 | ||||
-rw-r--r-- | mail/mail-component.c | 1 |
7 files changed, 450 insertions, 537 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 9bb351e24a..b56c17c16f 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,9 +1,44 @@ 2003-12-02 Jeffrey Stedfast <fejj@ximian.com> + * em-folder-tree-model.c (drop_uid_list): Moved here. + (drop_folder): Moved here. + (import_message_rfc822): Moved here. + (drop_message_rfc822): Moved here. + (drop_text_uri_list): Moved here. + (model_drag_data_received): Moved the logic from em-folder-tree.c + into here. + (model_row_drop_possible): Same. + (model_row_draggable): Same. + (drag_text_uri_list): Moved here. + (model_drag_data_get): Moved logic here. + (model_drag_data_delete): Moved logic here. + + * em-folder-tree.c (drag_data_get_cb): Pass the full_name to + camel_store_get_folder() rather than the path. + (drag_data_received_cb): Same. + (drop_uid_list): Removed. + (drop_folder): Removed. + (import_message_rfc822): Removed. + (drop_message_rfc822): Removed. + (drop_text_uri_list): Removed. + (drag_data_received_cb): Removed. + (row_drop_possible_cb): Removed. + (row_draggable_cb): Removed. + (drag_text_uri_list): Removed. + (drag_data_get_cb): Removed. + (drag_data_delete_cb): Removed. + (em_folder_tree_enable_drag_and_drop): Don't connect to any of the + drag & drop signals, they don't exist anymore. + + * mail-component.c (impl_createControls): Enable drag-and-drop. + * em-folder-tree.c (em_folder_tree_new_with_model): Connect to the loading row signal. (loading_row_cb): Expand the path if needed. (em_folder_tree_destroy): Disconnect from the loading-row signal. + (em_folder_tree_enable_drag_and_drop): New function to enable + drag-and-drop. + (em_folder_tree_new): Remove drag-and-drop setup code. * em-folder-tree-model.c (em_folder_tree_model_class_init): Define the loading-row signal. diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index 563f53dce0..df6cf80e73 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -32,14 +32,22 @@ #include <fcntl.h> #include <errno.h> +#include <e-util/e-mktemp.h> + #include <camel/camel-file-utils.h> #include "mail-config.h" +#include "mail-session.h" +#include "mail-tools.h" + +#include "em-utils.h" #include "em-marshal.h" #include "em-folder-tree-model.h" +#define d(x) x + static GType col_types[] = { G_TYPE_STRING, /* display name */ G_TYPE_POINTER, /* store object */ @@ -64,15 +72,15 @@ static void tree_drag_source_iface_init (GtkTreeDragSourceIface *iface); /* drag & drop iface methods */ static gboolean model_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, - GtkSelectionData *selection_data); + GtkSelectionData *selection); static gboolean model_row_drop_possible (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, - GtkSelectionData *selection_data); + GtkSelectionData *selection); static gboolean model_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *src_path); static gboolean model_drag_data_get (GtkTreeDragSource *drag_source, GtkTreePath *src_path, - GtkSelectionData *selection_data); + GtkSelectionData *selection); static gboolean model_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *src_path); @@ -160,59 +168,6 @@ em_folder_tree_model_class_init (EMFolderTreeModelClass *klass) G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); - - signals[DRAG_DATA_RECEIVED] = - g_signal_new ("drag-data-received", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_NO_HOOKS, - G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_received), - NULL, NULL, - em_marshal_BOOLEAN__POINTER_POINTER, - G_TYPE_BOOLEAN, 2, - G_TYPE_POINTER, - G_TYPE_POINTER); - - signals[ROW_DROP_POSSIBLE] = - g_signal_new ("row-drop-possible", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_NO_HOOKS, - G_STRUCT_OFFSET (EMFolderTreeModelClass, row_drop_possible), - NULL, NULL, - em_marshal_BOOLEAN__POINTER_POINTER, - G_TYPE_BOOLEAN, 2, - G_TYPE_POINTER, - G_TYPE_POINTER); - - signals[ROW_DRAGGABLE] = - g_signal_new ("row-draggable", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_NO_HOOKS, - G_STRUCT_OFFSET (EMFolderTreeModelClass, row_draggable), - NULL, NULL, - em_marshal_BOOLEAN__POINTER, - G_TYPE_BOOLEAN, 1, - G_TYPE_POINTER); - - signals[DRAG_DATA_GET] = - g_signal_new ("drag-data-get", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_NO_HOOKS, - G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_get), - NULL, NULL, - em_marshal_BOOLEAN__POINTER_POINTER, - G_TYPE_BOOLEAN, 2, - G_TYPE_POINTER, - G_TYPE_POINTER); - - signals[DRAG_DATA_DELETE] = - g_signal_new ("drag-data-delete", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_NO_HOOKS, - G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_delete), - NULL, NULL, - em_marshal_BOOLEAN__POINTER, - G_TYPE_BOOLEAN, 1, - G_TYPE_POINTER); } static void @@ -310,59 +265,427 @@ tree_drag_source_iface_init (GtkTreeDragSourceIface *iface) } +static void +drop_uid_list (CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) +{ + CamelFolder *src; + GPtrArray *uids; + char *src_uri; + + em_utils_selection_get_uidlist (selection, &src_uri, &uids); + + if (!(src = mail_tool_uri_to_folder (src_uri, 0, ex))) { + em_utils_uids_free (uids); + g_free (src_uri); + return; + } + + g_free (src_uri); + + camel_folder_transfer_messages_to (src, uids, dest, NULL, move, ex); + em_utils_uids_free (uids); + camel_object_unref (src); +} + +static void +drop_folder (CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) +{ + CamelFolder *src; + + /* get the folder being dragged */ + if (!(src = mail_tool_uri_to_folder (selection->data, 0, ex))) + return; + + if (src->parent_store == dest->parent_store && move) { + /* simple rename() action */ + char *old_name, *new_name; + + old_name = g_strdup (src->full_name); + new_name = g_strdup_printf ("%s/%s", dest->full_name, src->name); + + camel_store_rename_folder (dest->parent_store, old_name, new_name, ex); + + g_free (old_name); + g_free (new_name); + } else { + /* copy the folder to the new location */ + CamelFolder *folder; + char *path; + + path = g_strdup_printf ("%s/%s", dest->full_name, src->name); + if ((folder = camel_store_get_folder (dest->parent_store, path, CAMEL_STORE_FOLDER_CREATE, ex))) { + GPtrArray *uids; + + uids = camel_folder_get_uids (src); + camel_folder_transfer_messages_to (src, uids, folder, NULL, FALSE, ex); + camel_folder_free_uids (src, uids); + + camel_object_unref (folder); + } + + g_free (path); + } + + camel_object_unref (src); +} + static gboolean -model_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data) +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 +drop_message_rfc822 (CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) +{ + CamelStream *stream; + gboolean scan_from; + + scan_from = selection->length > 5 && !strncmp (selection->data, "From ", 5); + stream = camel_stream_mem_new_with_buffer (selection->data, selection->length); + + import_message_rfc822 (dest, stream, scan_from, ex); + + camel_object_unref (stream); +} + +static void +drop_text_uri_list (CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) +{ + char **urls, *url, *tmp; + CamelStream *stream; + CamelURL *uri; + int fd, i; + + tmp = g_strndup (selection->data, selection->length); + urls = g_strsplit (tmp, "\n", 0); + g_free (tmp); + + for (i = 0; urls[i] != NULL; i++) { + /* get the path component */ + url = g_strstrip (urls[i]); + uri = camel_url_new (url, NULL); + g_free (url); + + if (!uri || strcmp (uri->protocol, "file") != 0) { + camel_url_free (uri); + continue; + } + + url = uri->path; + uri->path = NULL; + camel_url_free (uri); + + if ((fd = open (url, O_RDONLY)) == -1) { + g_free (url); + continue; + } + + stream = camel_stream_fs_new_with_fd (fd); + if (!import_message_rfc822 (dest, stream, TRUE, ex)) { + /* FIXME: should we abort now? or continue? */ + /* for now lets just continue... */ + camel_exception_clear (ex); + } + + camel_object_unref (stream); + g_free (url); + } + + g_free (urls); +} + + +static gboolean +model_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection) { EMFolderTreeModel *model = (EMFolderTreeModel *) drag_dest; - gboolean retval = FALSE; + const char *full_name; + CamelFolder *folder; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path; + + /* this means we are receiving no data */ + if (!selection->data || selection->length == -1) + return FALSE; + + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path)) + return FALSE; + + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, -1); + + /* make sure user isn't try to drop on a placeholder row */ + if (path == NULL) + return FALSE; + + full_name = path[0] == '/' ? path + 1 : path; + + camel_exception_init (&ex); + if ((folder = camel_store_get_folder (store, full_name, 0, &ex))) { + /* FIXME: would have been nicer if we could 'move' + * messages and/or folders. but alas, gtktreeview + * drag&drop sucks ass and doesn't give us the + * context->action to check for GDK_ACTION_MOVE, so we + * can't. Yay. */ + gboolean move = FALSE; + + if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { + /* import a list of uids from another evo folder */ + drop_uid_list (folder, move, selection, &ex); + d(printf ("* dropped a x-uid-list\n")); + } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + /* copy or move (aka rename) a folder */ + drop_folder (folder, move, selection, &ex); + d(printf ("* dropped a x-folder\n")); + } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { + /* import a message/rfc822 stream */ + drop_message_rfc822 (folder, selection, &ex); + d(printf ("* dropped a message/rfc822\n")); + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + /* import an mbox, maildir, or mh folder? */ + drop_text_uri_list (folder, selection, &ex); + d(printf ("* dropped a text/uri-list\n")); + } else { + g_assert_not_reached (); + } + } - g_signal_emit (model, signals[DRAG_DATA_RECEIVED], 0, dest_path, selection_data, &retval); + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } - return retval; + return TRUE; } static gboolean -model_row_drop_possible (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data) +model_row_drop_possible (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection) { EMFolderTreeModel *model = (EMFolderTreeModel *) drag_dest; - gboolean retval = FALSE; + gboolean is_store; + GtkTreeIter iter; - g_signal_emit (model, signals[ROW_DROP_POSSIBLE], 0, dest_path, selection_data, &retval); + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path)) + return FALSE; - return retval; + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); + + if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + return TRUE; + } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else { + g_assert_not_reached (); + return FALSE; + } } static gboolean model_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *src_path) { EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; - gboolean retval = FALSE; + gboolean is_store; + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) + return FALSE; + + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); + + return !is_store; +} + +static void +drag_text_uri_list (CamelFolder *src, GtkSelectionData *selection, CamelException *ex) +{ + CamelFolder *dest; + const char *tmpdir; + CamelStore *store; + GPtrArray *uids; + GString *url; + + if (!(tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX"))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary directory: %s"), + g_strerror (errno)); + return; + } + + url = g_string_new ("mbox:"); + g_string_append (url, tmpdir); + if (!(store = camel_session_get_store (session, url->str, ex))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary mbox store: %s"), + camel_exception_get_description (ex)); + g_string_free (url, TRUE); + + return; + } - g_signal_emit (model, signals[ROW_DRAGGABLE], 0, src_path, &retval); + if (!(dest = camel_store_get_folder (store, "mbox", CAMEL_STORE_FOLDER_CREATE, ex))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary mbox folder: %s"), + camel_exception_get_description (ex)); + + camel_object_unref (store); + g_string_free (url, TRUE); + + return; + } + + camel_object_unref (store); + uids = camel_folder_get_uids (src); - return retval; + camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, ex); + if (camel_exception_is_set (ex)) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not copy messages to temporary mbox folder: %s"), + camel_exception_get_description (ex)); + } else { + /* replace "mbox:" with "file:" */ + memcpy (url->str, "file", 4); + g_string_append (url, "\r\n"); + gtk_selection_data_set (selection, selection->target, 8, url->str, url->len); + } + + camel_folder_free_uids (src, uids); + camel_object_unref (dest); + g_string_free (url, TRUE); } static gboolean -model_drag_data_get (GtkTreeDragSource *drag_source, GtkTreePath *src_path, GtkSelectionData *selection_data) +model_drag_data_get (GtkTreeDragSource *drag_source, GtkTreePath *src_path, GtkSelectionData *selection) { EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; - gboolean retval = FALSE; + const char *full_name; + CamelFolder *folder; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path, *uri; + + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) + return FALSE; - g_signal_emit (model, signals[DRAG_DATA_GET], 0, src_path, selection_data, &retval); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, + COL_STRING_URI, &uri, -1); - return retval; + /* make sure user isn't try to drag on a placeholder row */ + if (path == NULL) + return FALSE; + + full_name = path[0] == '/' ? path + 1 : path; + + camel_exception_init (&ex); + + if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + /* dragging to a new location in the folder tree */ + gtk_selection_data_set (selection, selection->target, 8, uri, strlen (uri) + 1); + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + /* dragging to nautilus or something, probably */ + if ((folder = camel_store_get_folder (store, full_name, 0, &ex))) { + drag_text_uri_list (folder, selection, &ex); + camel_object_unref (folder); + } + } else { + g_assert_not_reached (); + } + + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } + + return TRUE; } static gboolean model_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *src_path) { EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; - gboolean retval = FALSE; + const char *full_name; + gboolean is_store; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path; + + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) + return FALSE; + + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, + COL_BOOL_IS_STORE, &is_store, -1); - g_signal_emit (model, signals[DRAG_DATA_DELETE], 0, src_path, &retval); + if (is_store) + return FALSE; + + full_name = path[0] == '/' ? path + 1 : path; - return retval; + camel_exception_init (&ex); + camel_store_delete_folder (store, full_name, &ex); + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } + + return TRUE; } diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h index 882b102d6e..3296af1ed1 100644 --- a/mail/em-folder-tree-model.h +++ b/mail/em-folder-tree-model.h @@ -92,21 +92,6 @@ struct _EMFolderTreeModelClass { void (* loading_row) (EMFolderTreeModel *model, GtkTreePath *path, GtkTreeIter *iter); - - gboolean (* drag_data_received) (EMFolderTreeModel *model, - GtkTreePath *dest_path, - GtkSelectionData *selection_data); - gboolean (* row_drop_possible) (EMFolderTreeModel *model, - GtkTreePath *dest_path, - GtkSelectionData *selection_data); - - gboolean (* row_draggable) (EMFolderTreeModel *model, - GtkTreePath *src_path); - gboolean (* drag_data_get) (EMFolderTreeModel *model, - GtkTreePath *src_path, - GtkSelectionData *selection_data); - gboolean (* drag_data_delete) (EMFolderTreeModel *model, - GtkTreePath *src_path); }; diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index 42ffcf0f1d..aac98704c1 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -75,9 +75,6 @@ struct _EMFolderTreePrivate { guint save_state_id; guint loading_row_id; - - /* dnd signal ids */ - guint ddr, rdp, rd, ddg, ddd; }; enum { @@ -322,36 +319,6 @@ em_folder_tree_destroy (GtkObject *obj) priv->loading_row_id = 0; } - if (priv->ddr != 0) { - g_signal_handler_disconnect (priv->model, priv->ddr); - priv->ddr = 0; - } - - if (priv->rdp != 0) { - g_signal_handler_disconnect (priv->model, priv->rdp); - priv->rdp = 0; - } - - if (priv->rd != 0) { - g_signal_handler_disconnect (priv->model, priv->rd); - priv->rd = 0; - } - - if (priv->ddg != 0) { - g_signal_handler_disconnect (priv->model, priv->ddg); - priv->ddg = 0; - } - - if (priv->ddd != 0) { - g_signal_handler_disconnect (priv->model, priv->ddd); - priv->ddd = 0; - } - - if (priv->save_state_id != 0) { - em_folder_tree_save_state ((EMFolderTree *) obj); - priv->save_state_id = 0; - } - priv->treeview = NULL; priv->model = NULL; @@ -418,411 +385,9 @@ em_folder_tree_construct (EMFolderTree *emft, EMFolderTreeModel *model) } -static void -drop_uid_list (EMFolderTree *emft, CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) -{ - CamelFolder *src; - GPtrArray *uids; - char *src_uri; - - em_utils_selection_get_uidlist (selection, &src_uri, &uids); - - if (!(src = mail_tool_uri_to_folder (src_uri, 0, ex))) { - em_utils_uids_free (uids); - g_free (src_uri); - return; - } - - g_free (src_uri); - - camel_folder_transfer_messages_to (src, uids, dest, NULL, move, ex); - em_utils_uids_free (uids); - camel_object_unref (src); -} - -static void -drop_folder (EMFolderTree *emft, CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) -{ - CamelFolder *src; - - /* get the folder being dragged */ - if (!(src = mail_tool_uri_to_folder (selection->data, 0, ex))) - return; - - if (src->parent_store == dest->parent_store && move) { - /* simple rename() action */ - char *old_name, *new_name; - - old_name = g_strdup (src->full_name); - new_name = g_strdup_printf ("%s/%s", dest->full_name, src->name); - - camel_store_rename_folder (dest->parent_store, old_name, new_name, ex); - - g_free (old_name); - g_free (new_name); - } else { - /* copy the folder to the new location */ - CamelFolder *folder; - char *path; - - path = g_strdup_printf ("%s/%s", dest->full_name, src->name); - if ((folder = camel_store_get_folder (dest->parent_store, path, CAMEL_STORE_FOLDER_CREATE, ex))) { - GPtrArray *uids; - - uids = camel_folder_get_uids (src); - camel_folder_transfer_messages_to (src, uids, folder, NULL, FALSE, ex); - camel_folder_free_uids (src, uids); - - camel_object_unref (folder); - } - - g_free (path); - } - - camel_object_unref (src); -} - -static gboolean -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 -drop_message_rfc822 (EMFolderTree *emft, CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) -{ - CamelStream *stream; - gboolean scan_from; - - scan_from = selection->length > 5 && !strncmp (selection->data, "From ", 5); - stream = camel_stream_mem_new_with_buffer (selection->data, selection->length); - - import_message_rfc822 (dest, stream, scan_from, ex); - - camel_object_unref (stream); -} - -static void -drop_text_uri_list (EMFolderTree *emft, CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) -{ - char **urls, *url, *tmp; - CamelStream *stream; - CamelURL *uri; - int fd, i; - - tmp = g_strndup (selection->data, selection->length); - urls = g_strsplit (tmp, "\n", 0); - g_free (tmp); - - for (i = 0; urls[i] != NULL; i++) { - /* get the path component */ - url = g_strstrip (urls[i]); - uri = camel_url_new (url, NULL); - g_free (url); - - if (!uri || strcmp (uri->protocol, "file") != 0) { - camel_url_free (uri); - continue; - } - - url = uri->path; - uri->path = NULL; - camel_url_free (uri); - - if ((fd = open (url, O_RDONLY)) == -1) { - g_free (url); - continue; - } - - stream = camel_stream_fs_new_with_fd (fd); - if (!import_message_rfc822 (dest, stream, TRUE, ex)) { - /* FIXME: should we abort now? or continue? */ - /* for now lets just continue... */ - camel_exception_clear (ex); - } - - camel_object_unref (stream); - g_free (url); - } - - g_free (urls); -} - -static gboolean -drag_data_received_cb (EMFolderTreeModel *model, GtkTreePath *dest_path, GtkSelectionData *selection, EMFolderTree *emft) -{ - CamelFolder *folder; - CamelStore *store; - CamelException ex; - GtkTreeIter iter; - char *path; - - /* this means we are receiving no data */ - if (!selection->data || selection->length == -1) - return FALSE; - - if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path)) - return FALSE; - - gtk_tree_model_get ((GtkTreeModel *) model, &iter, - COL_POINTER_CAMEL_STORE, &store, - COL_STRING_FOLDER_PATH, &path, -1); - - camel_exception_init (&ex); - if ((folder = camel_store_get_folder (store, path, 0, &ex))) { - /* FIXME: would have been nicer if we could 'move' - * messages and/or folders. but alas, gtktreeview - * drag&drop sucks ass and doesn't give us the - * context->action to check for GDK_ACTION_MOVE, so we - * can't. Yay. */ - gboolean move = FALSE; - - if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { - /* import a list of uids from another evo folder */ - drop_uid_list (emft, folder, move, selection, &ex); - d(printf ("* dropped a x-uid-list\n")); - } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { - /* copy or move (aka rename) a folder */ - drop_folder (emft, folder, move, selection, &ex); - d(printf ("* dropped a x-folder\n")); - } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { - /* import a message/rfc822 stream */ - drop_message_rfc822 (emft, folder, selection, &ex); - d(printf ("* dropped a message/rfc822\n")); - } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { - /* import an mbox, maildir, or mh folder? */ - drop_text_uri_list (emft, folder, selection, &ex); - d(printf ("* dropped a text/uri-list\n")); - } else { - g_assert_not_reached (); - } - } - - if (camel_exception_is_set (&ex)) { - /* FIXME: error dialog? */ - camel_exception_clear (&ex); - return FALSE; - } - - return TRUE; -} - -static gboolean -row_drop_possible_cb (EMFolderTreeModel *model, GtkTreePath *dest_path, GtkSelectionData *selection, EMFolderTree *emft) -{ - GtkTreeIter iter; - gboolean is_store; - - if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path)) - return FALSE; - - gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); - - if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { - if (is_store) - return FALSE; - - return TRUE; - } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { - return TRUE; - } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { - if (is_store) - return FALSE; - - return TRUE; - } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { - if (is_store) - return FALSE; - - return TRUE; - } else { - g_assert_not_reached (); - return FALSE; - } -} - -static gboolean -row_draggable_cb (EMFolderTreeModel *model, GtkTreePath *src_path, EMFolderTree *emft) -{ - GtkTreeIter iter; - gboolean is_store; - - if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) - return FALSE; - - gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); - - return !is_store; -} - -static void -drag_text_uri_list (EMFolderTree *emft, CamelFolder *src, GtkSelectionData *selection, CamelException *ex) -{ - CamelFolder *dest; - const char *tmpdir; - CamelStore *store; - GPtrArray *uids; - GString *url; - - if (!(tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX"))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create temporary directory: %s"), - g_strerror (errno)); - return; - } - - url = g_string_new ("mbox:"); - g_string_append (url, tmpdir); - if (!(store = camel_session_get_store (session, url->str, ex))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create temporary mbox store: %s"), - camel_exception_get_description (ex)); - g_string_free (url, TRUE); - - return; - } - - if (!(dest = camel_store_get_folder (store, "mbox", CAMEL_STORE_FOLDER_CREATE, ex))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create temporary mbox folder: %s"), - camel_exception_get_description (ex)); - - camel_object_unref (store); - g_string_free (url, TRUE); - - return; - } - - camel_object_unref (store); - uids = camel_folder_get_uids (src); - - camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, ex); - if (camel_exception_is_set (ex)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not copy messages to temporary mbox folder: %s"), - camel_exception_get_description (ex)); - } else { - /* replace "mbox:" with "file:" */ - memcpy (url->str, "file", 4); - g_string_append (url, "\r\n"); - gtk_selection_data_set (selection, selection->target, 8, url->str, url->len); - } - - camel_folder_free_uids (src, uids); - camel_object_unref (dest); - g_string_free (url, TRUE); -} - -static gboolean -drag_data_get_cb (EMFolderTreeModel *model, GtkTreePath *src_path, GtkSelectionData *selection, EMFolderTree *emft) -{ - CamelFolder *folder; - CamelStore *store; - CamelException ex; - GtkTreeIter iter; - char *path, *uri; - - if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) - return FALSE; - - gtk_tree_model_get ((GtkTreeModel *) model, &iter, - COL_POINTER_CAMEL_STORE, &store, - COL_STRING_FOLDER_PATH, &path, - COL_STRING_URI, &uri, -1); - - camel_exception_init (&ex); - - if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { - /* dragging to a new location in the folder tree */ - gtk_selection_data_set (selection, selection->target, 8, uri, strlen (uri) + 1); - } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { - /* dragging to nautilus or something, probably */ - if ((folder = camel_store_get_folder (store, path, 0, &ex))) { - drag_text_uri_list (emft, folder, selection, &ex); - camel_object_unref (folder); - } - } else { - g_assert_not_reached (); - } - - if (camel_exception_is_set (&ex)) { - /* FIXME: error dialog? */ - camel_exception_clear (&ex); - return FALSE; - } - - return TRUE; -} - -static gboolean -drag_data_delete_cb (EMFolderTreeModel *model, GtkTreePath *src_path, EMFolderTree *emft) -{ - gboolean is_store; - CamelStore *store; - CamelException ex; - GtkTreeIter iter; - char *path; - - if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path)) - return FALSE; - - gtk_tree_model_get ((GtkTreeModel *) model, &iter, - COL_POINTER_CAMEL_STORE, &store, - COL_STRING_FOLDER_PATH, &path, - COL_BOOL_IS_STORE, &is_store, -1); - - if (is_store) - return FALSE; - - camel_exception_init (&ex); - camel_store_delete_folder (store, path, &ex); - if (camel_exception_is_set (&ex)) { - /* FIXME: error dialog? */ - camel_exception_clear (&ex); - return FALSE; - } - - return TRUE; -} - - GtkWidget * em_folder_tree_new (void) { - struct _EMFolderTreePrivate *priv; EMFolderTreeModel *model; EMFolderTree *emft; @@ -830,18 +395,6 @@ em_folder_tree_new (void) emft = (EMFolderTree *) em_folder_tree_new_with_model (model); g_object_unref (model); - priv = emft->priv; - priv->ddr = g_signal_connect (model, "drag-data-received", G_CALLBACK (drag_data_received_cb), emft); - priv->rdp = g_signal_connect (model, "row-drop-possible", G_CALLBACK (row_drop_possible_cb), emft); - priv->rd = g_signal_connect (model, "row-draggable", G_CALLBACK (row_draggable_cb), emft); - priv->ddg = g_signal_connect (model, "drag-data-get", G_CALLBACK (drag_data_get_cb), emft); - priv->ddd = g_signal_connect (model, "drag-data-delete", G_CALLBACK (drag_data_delete_cb), emft); - - gtk_tree_view_enable_model_drag_source (priv->treeview, 0, drag_types, num_drag_types, - GDK_ACTION_COPY | GDK_ACTION_MOVE); - gtk_tree_view_enable_model_drag_dest (priv->treeview, drop_types, num_drop_types, - GDK_ACTION_COPY | GDK_ACTION_MOVE); - return (GtkWidget *) emft; } @@ -959,6 +512,21 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model) } +void +em_folder_tree_enable_drag_and_drop (EMFolderTree *emft) +{ + struct _EMFolderTreePrivate *priv; + + g_return_if_fail (EM_IS_FOLDER_TREE (emft)); + + priv = emft->priv; + gtk_tree_view_enable_model_drag_source (priv->treeview, 0, drag_types, num_drag_types, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_tree_view_enable_model_drag_dest (priv->treeview, drop_types, num_drop_types, + GDK_ACTION_COPY | GDK_ACTION_MOVE); +} + + #if 0 static void dump_fi (CamelFolderInfo *fi, int depth) diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h index 71971b6585..c532f24314 100644 --- a/mail/em-folder-tree.h +++ b/mail/em-folder-tree.h @@ -63,6 +63,8 @@ GType em_folder_tree_get_type (void); GtkWidget *em_folder_tree_new (void); GtkWidget *em_folder_tree_new_with_model (EMFolderTreeModel *model); +void em_folder_tree_enable_drag_and_drop (EMFolderTree *emft); + void em_folder_tree_set_selected (EMFolderTree *emft, const char *uri); const char *em_folder_tree_get_selected_uri (EMFolderTree *emft); const char *em_folder_tree_get_selected_path (EMFolderTree *emft); diff --git a/mail/em-marshal.list b/mail/em-marshal.list index 00fe377898..aed944ea0f 100644 --- a/mail/em-marshal.list +++ b/mail/em-marshal.list @@ -1,5 +1,4 @@ BOOLEAN:BOXED,POINTER,POINTER -BOOLEAN:POINTER,POINTER VOID:STRING,STRING BOOLEAN:POINTER VOID:POINTER,POINTER diff --git a/mail/mail-component.c b/mail/mail-component.c index 0e3318acf9..3967ed8a1b 100644 --- a/mail/mail-component.c +++ b/mail/mail-component.c @@ -340,6 +340,7 @@ impl_createControls (PortableServer_Servant servant, view_widget = em_folder_browser_new (); tree_widget = (GtkWidget *) em_folder_tree_new_with_model (priv->model); + em_folder_tree_enable_drag_and_drop ((EMFolderTree *) tree_widget); em_format_set_session ((EMFormat *) ((EMFolderView *) view_widget)->preview, session); statusbar_widget = e_task_bar_new (); |