diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2003-12-03 07:29:09 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2003-12-03 07:29:09 +0800 |
commit | e0097e7f47f7bdd546b3d705d2dcf0893d29e3a2 (patch) | |
tree | a17565bce951eca581d0e76aa00fbec5ce670645 /mail/em-folder-tree-model.c | |
parent | a0b2261343a7938b4c85f8659216b9df1c81769b (diff) | |
download | gsoc2013-evolution-e0097e7f47f7bdd546b3d705d2dcf0893d29e3a2.tar.gz gsoc2013-evolution-e0097e7f47f7bdd546b3d705d2dcf0893d29e3a2.tar.zst gsoc2013-evolution-e0097e7f47f7bdd546b3d705d2dcf0893d29e3a2.zip |
Moved here. (drop_folder): Moved here. (import_message_rfc822): Moved
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.
(em_folder_tree_model_set_folder_info): emit the loading-row signal.
svn path=/trunk/; revision=23590
Diffstat (limited to 'mail/em-folder-tree-model.c')
-rw-r--r-- | mail/em-folder-tree-model.c | 471 |
1 files changed, 397 insertions, 74 deletions
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; } |