aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2004-02-09 21:11:51 +0800
committerMichael Zucci <zucchi@src.gnome.org>2004-02-09 21:11:51 +0800
commit67aa7010610fced90d25618f94e6caf7df5749cb (patch)
treef98d92cfa162d4e197cb975d2175493bafc162de /mail
parent4287c8e129507c5b4120f0038f2f130130a81633 (diff)
downloadgsoc2013-evolution-67aa7010610fced90d25618f94e6caf7df5749cb.tar.gz
gsoc2013-evolution-67aa7010610fced90d25618f94e6caf7df5749cb.tar.zst
gsoc2013-evolution-67aa7010610fced90d25618f94e6caf7df5749cb.zip
merged in code from em_folder_tree_model_drag_data_delete.
2004-02-09 Not Zed <NotZed@Ximian.com> * em-folder-tree.c (tree_drag_data_delete): merged in code from em_folder_tree_model_drag_data_delete. (tree_drag_data_get): similar. (tree_drag_data_received): similar. (drag_text_uri_list): removed, use em_utils_selection_set_urilist in tree_drag_data_get instead. (em_folder_tree_enable_drag_and_drop): merged in em_folder_tree_model_set_drag_drop_types. (tree_drag_motion): merge in drop_possible, handle qualifiers, and return the right type. (em_folder_tree_model_row_drop_target): rename to emft_drop_target, and make private. Beefed up substantially, handles illogical drops, dropping on to special folders and properly handling vfolder uri's (at least within the same tree instance). * em-folder-tree-model.c: Moved all of the DND stuff to em-folder-tree, where it belongs, made it all static. Should allow for some sharing of code too. svn path=/trunk/; revision=24679
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog20
-rw-r--r--mail/em-folder-tree-model.c596
-rw-r--r--mail/em-folder-tree-model.h11
-rw-r--r--mail/em-folder-tree.c626
4 files changed, 607 insertions, 646 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index ca85436fe1..7924b6c630 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,5 +1,25 @@
2004-02-09 Not Zed <NotZed@Ximian.com>
+ * em-folder-tree.c (tree_drag_data_delete): merged in code from
+ em_folder_tree_model_drag_data_delete.
+ (tree_drag_data_get): similar.
+ (tree_drag_data_received): similar.
+ (drag_text_uri_list): removed, use em_utils_selection_set_urilist
+ in tree_drag_data_get instead.
+ (em_folder_tree_enable_drag_and_drop): merged in
+ em_folder_tree_model_set_drag_drop_types.
+ (tree_drag_motion): merge in drop_possible, handle qualifiers, and
+ return the right type.
+ (em_folder_tree_model_row_drop_target): rename to
+ emft_drop_target, and make private. Beefed up substantially,
+ handles illogical drops, dropping on to special folders and
+ properly handling vfolder uri's (at least within the same tree
+ instance).
+
+ * em-folder-tree-model.c: Moved all of the DND stuff to
+ em-folder-tree, where it belongs, made it all static. Should
+ allow for some sharing of code too.
+
* em-format-quote.c (emfq_format_message): just print the \n after
the credits in the same printf, rather than adding an else. Add a
<br> too, otherwise it has no effect.
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index c9490628e1..3c1399ba74 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -59,38 +59,6 @@ static GType col_types[] = {
G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */
};
-
-/* Drag & Drop types */
-enum DndDragType {
- DND_DRAG_TYPE_FOLDER, /* drag an evo folder */
- DND_DRAG_TYPE_TEXT_URI_LIST, /* drag to an mbox file */
- NUM_DRAG_TYPES
-};
-
-enum DndDropType {
- DND_DROP_TYPE_UID_LIST, /* drop a list of message uids */
- DND_DROP_TYPE_FOLDER, /* drop an evo folder */
- DND_DROP_TYPE_MESSAGE_RFC822, /* drop a message/rfc822 stream */
- DND_DROP_TYPE_TEXT_URI_LIST, /* drop an mbox file */
- NUM_DROP_TYPES
-};
-
-static GtkTargetEntry drag_types[] = {
- { "x-folder", 0, DND_DRAG_TYPE_FOLDER },
- { "text/uri-list", 0, DND_DRAG_TYPE_TEXT_URI_LIST },
-};
-
-static GtkTargetEntry drop_types[] = {
- { "x-uid-list" , 0, DND_DROP_TYPE_UID_LIST },
- { "x-folder", 0, DND_DROP_TYPE_FOLDER },
- { "message/rfc822", 0, DND_DROP_TYPE_MESSAGE_RFC822 },
- { "text/uri-list", 0, DND_DROP_TYPE_TEXT_URI_LIST },
-};
-
-static GdkAtom drag_atoms[NUM_DRAG_TYPES];
-static GdkAtom drop_atoms[NUM_DROP_TYPES];
-
-
/* GObject virtual method overrides */
static void em_folder_tree_model_class_init (EMFolderTreeModelClass *klass);
static void em_folder_tree_model_init (EMFolderTreeModel *model);
@@ -109,11 +77,8 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0, };
-
-
static GtkTreeStoreClass *parent_class = NULL;
-
GType
em_folder_tree_model_get_type (void)
{
@@ -175,12 +140,6 @@ em_folder_tree_model_class_init (EMFolderTreeModelClass *klass)
G_TYPE_NONE, 2,
G_TYPE_POINTER,
G_TYPE_POINTER);
-
- for (i = 0; i < NUM_DRAG_TYPES; i++)
- drag_atoms[i] = gdk_atom_intern (drag_types[i].target, FALSE);
-
- for (i = 0; i < NUM_DROP_TYPES; i++)
- drop_atoms[i] = gdk_atom_intern (drop_types[i].target, FALSE);
}
static int
@@ -1000,558 +959,3 @@ em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *sto
gtk_tree_store_set ((GtkTreeStore *) model, &iter, COL_UINT_UNREAD, unread, -1);
}
-
-struct _DragDataReceivedAsync {
- struct _mail_msg msg;
-
- /* input data */
- GdkDragContext *context;
-
- union {
- CamelStreamMem *rfc822;
- char *folder;
- char **urilist;
- struct {
- char *uri;
- GPtrArray *uids;
- } uidlist;
- } selection;
-
- CamelStore *store;
- char *full_name;
- gboolean move;
- guint info;
-
- /* output data */
- gboolean moved;
-};
-
-/* Drag & Drop methods */
-static void
-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
-drop_folder(struct _DragDataReceivedAsync *m)
-{
- CamelFolder *src;
- char *new_name;
-
- d(printf(" * Drop folder '%s' onto '%s'\n", m->selection.folder, m->full_name));
-
- if (!(src = mail_tool_uri_to_folder(m->selection.folder, 0, &m->msg.ex)))
- return;
-
- /* handles dropping to the root properly */
- if (m->full_name[0])
- new_name = g_strdup_printf("%s/%s", m->full_name, src->name);
- else
- new_name = g_strdup(src->name);
-
- if (src->parent_store == m->store && m->move) {
- /* simple case, rename */
- camel_store_rename_folder(m->store, src->full_name, new_name, &m->msg.ex);
- m->moved = !camel_exception_is_set (&m->msg.ex);
- } else {
- CamelFolder *dest;
-
- /* copy the folder to the new location */
- if ((dest = camel_store_get_folder(m->store, new_name, CAMEL_STORE_FOLDER_CREATE, &m->msg.ex))) {
- GPtrArray *uids;
-
- uids = camel_folder_get_uids (src);
- camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, &m->msg.ex);
- camel_folder_free_uids (src, uids);
-
- camel_object_unref (dest);
- }
- }
-
- g_free(new_name);
- 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(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);
- import_message_rfc822(dest, (CamelStream *)m->selection.rfc822, scan_from, &m->msg.ex);
-}
-
-static void
-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 = import_message_rfc822(dest, stream, TRUE, &m->msg.ex);
- camel_object_unref(stream);
- }
- camel_url_free(url);
- }
-}
-
-static void
-emftm_drag_data_received_async__drop (struct _mail_msg *mm)
-{
- struct _DragDataReceivedAsync *m = (struct _DragDataReceivedAsync *) mm;
- CamelFolder *folder;
-
- /* for types other than folder, we can't drop to the root path */
- if (m->info == DND_DROP_TYPE_FOLDER) {
- /* copy or move (aka rename) a folder */
- drop_folder(m);
- } else if (m->full_name[0] == 0) {
- camel_exception_set (&mm->ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot drop message(s) into toplevel store"));
- } else if ((folder = camel_store_get_folder (m->store, m->full_name, 0, &mm->ex))) {
- switch (m->info) {
- case DND_DROP_TYPE_UID_LIST:
- /* import a list of uids from another evo folder */
- drop_uid_list(m, folder);
- break;
- case DND_DROP_TYPE_MESSAGE_RFC822:
- /* import a message/rfc822 stream */
- drop_message_rfc822(m, folder);
- break;
- case DND_DROP_TYPE_TEXT_URI_LIST:
- /* import an mbox, maildir, or mh folder? */
- drop_text_uri_list(m, folder);
- break;
- default:
- g_assert_not_reached ();
- }
- camel_object_unref(folder);
- }
-}
-
-static void
-emftm_drag_data_received_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;
-
- gtk_drag_finish (m->context, success, delete, GDK_CURRENT_TIME);
-}
-
-static void
-emftm_drag_data_received_async__free (struct _mail_msg *mm)
-{
- struct _DragDataReceivedAsync *m = (struct _DragDataReceivedAsync *) mm;
-
- g_object_unref(m->context);
- 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();
- }
-}
-
-static struct _mail_msg_op drag_data_received_async_op = {
- NULL,
- emftm_drag_data_received_async__drop,
- emftm_drag_data_received_async__done,
- emftm_drag_data_received_async__free,
-};
-
-void
-em_folder_tree_model_drag_data_received (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *dest_path,
- GtkSelectionData *selection, guint info)
-{
- struct _DragDataReceivedAsync *m;
- const char *full_name;
- CamelStore *store;
- GtkTreeIter iter;
- char *path, *tmp;
- int i;
-
- /* this means we are receiving no data */
- if (!selection->data || selection->length == -1) {
- gtk_drag_finish (context, FALSE, FALSE, GDK_CURRENT_TIME);
- return;
- }
-
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path)) {
- gtk_drag_finish (context, FALSE, FALSE, GDK_CURRENT_TIME);
- return;
- }
-
- 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) {
- gtk_drag_finish (context, FALSE, FALSE, GDK_CURRENT_TIME);
- return;
- }
-
- full_name = path[0] == '/' ? path + 1 : path;
-
- g_object_ref (context);
- camel_object_ref (store);
-
- m = mail_msg_new (&drag_data_received_async_op, NULL, sizeof (struct _DragDataReceivedAsync));
- m->context = context;
- m->store = store;
- m->full_name = g_strdup (full_name);
- m->move = context->action == GDK_ACTION_MOVE;
- 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();
- }
-
- e_thread_put (mail_thread_new, (EMsg *) m);
-}
-
-
-GdkDragAction
-em_folder_tree_model_row_drop_possible (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path)
-{
- GdkAtom target;
- int i;
-
- target = em_folder_tree_model_row_drop_target (model, context, path);
- if (target == GDK_NONE)
- return 0;
-
- for (i = 0; i < NUM_DROP_TYPES; i++) {
- if (drop_atoms[i] == target) {
- switch (i) {
- case DND_DROP_TYPE_FOLDER:
- return GDK_ACTION_MOVE;
- default:
- return GDK_ACTION_COPY;
- }
- }
- }
-
- return 0;
-}
-
-
-GdkAtom
-em_folder_tree_model_row_drop_target (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path)
-{
- gboolean is_store;
- GtkTreeIter iter;
- GList *targets;
- char *uri;
-
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path))
- return GDK_NONE;
-
- gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, COL_STRING_URI, &uri, -1);
-
- /* can't drag&drop into/onto a vfolder or the vfolder store */
- if (uri && !strncmp (uri, "vfolder:", 8)) {
- /* FIXME: ...unless the source is a vfolder */
- return GDK_NONE;
- }
-
- targets = context->targets;
-
- if (is_store) {
- /* can only drop x-folders into a store */
- GdkAtom xfolder;
-
- xfolder = drop_atoms[DND_DROP_TYPE_FOLDER];
- while (targets != NULL) {
- if (targets->data == (gpointer) xfolder)
- return xfolder;
-
- targets = targets->next;
- }
- } else {
- /* can drop anything into folders */
- int i;
-
- while (targets != NULL) {
- for (i = 0; i < NUM_DROP_TYPES; i++) {
- if (targets->data == (gpointer) drop_atoms[i])
- return drop_atoms[i];
- }
-
- targets = targets->next;
- }
- }
-
- return GDK_NONE;
-}
-
-
-gboolean
-em_folder_tree_model_row_draggable (EMFolderTreeModel *model, GtkTreePath *path)
-{
- gboolean is_store;
- GtkTreeIter iter;
-
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, 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;
- }
-
- 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, drag_atoms[DND_DRAG_TYPE_TEXT_URI_LIST], 8, url->str, url->len);
- }
-
- camel_folder_free_uids (src, uids);
- camel_object_unref (dest);
- g_string_free (url, TRUE);
-}
-
-void
-em_folder_tree_model_drag_data_get (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *src_path, GtkSelectionData *selection, guint info)
-{
- 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;
-
- gtk_tree_model_get ((GtkTreeModel *) model, &iter,
- COL_POINTER_CAMEL_STORE, &store,
- COL_STRING_FOLDER_PATH, &path,
- COL_STRING_URI, &uri, -1);
-
- /* make sure user isn't trying to drag on a placeholder row */
- if (path == NULL)
- return;
-
- full_name = path[0] == '/' ? path + 1 : path;
-
- camel_exception_init (&ex);
-
- switch (info) {
- case DND_DRAG_TYPE_FOLDER:
- /* dragging to a new location in the folder tree */
- printf ("dragging uri: %s\n", uri);
- gtk_selection_data_set (selection, drag_atoms[info], 8, uri, strlen (uri) + 1);
- break;
- case DND_DRAG_TYPE_TEXT_URI_LIST:
- /* dragging to nautilus or something, probably */
- /* Note: this doesn't need to be done in another
- * thread because the folder should already be
- * cached */
- if ((folder = camel_store_get_folder (store, full_name, 0, &ex))) {
- drag_text_uri_list (folder, selection, &ex);
- camel_object_unref (folder);
- }
- break;
- default:
- g_assert_not_reached ();
- }
-
- if (camel_exception_is_set (&ex)) {
- camel_exception_clear (&ex);
- return;
- }
-
- return;
-}
-
-
-gboolean
-em_folder_tree_model_drag_data_delete (EMFolderTreeModel *model, GtkTreePath *src_path)
-{
- 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);
-
- if (is_store)
- return FALSE;
-
- full_name = path[0] == '/' ? path + 1 : path;
-
- camel_exception_init (&ex);
- camel_store_delete_folder (store, full_name, &ex);
- if (camel_exception_is_set (&ex)) {
- camel_exception_clear (&ex);
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-void
-em_folder_tree_model_set_drag_drop_types (EMFolderTreeModel *model, GtkWidget *widget)
-{
- gtk_drag_source_set (widget, GDK_BUTTON1_MASK, drag_types, NUM_DRAG_TYPES,
- GDK_ACTION_COPY | GDK_ACTION_MOVE);
- gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, drop_types,
- NUM_DROP_TYPES, GDK_ACTION_COPY | GDK_ACTION_MOVE);
-}
diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h
index c5afc9f98e..b21b406125 100644
--- a/mail/em-folder-tree-model.h
+++ b/mail/em-folder-tree-model.h
@@ -124,17 +124,6 @@ void em_folder_tree_model_save_expanded (EMFolderTreeModel *model);
void em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *store, const char *path, int unread);
-/* Drag & Drop stuff */
-void em_folder_tree_model_drag_data_received (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path,
- GtkSelectionData *selection, guint info);
-GdkDragAction em_folder_tree_model_row_drop_possible (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path);
-GdkAtom em_folder_tree_model_row_drop_target (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path);
-gboolean em_folder_tree_model_row_draggable (EMFolderTreeModel *model, GtkTreePath *path);
-void em_folder_tree_model_drag_data_get (EMFolderTreeModel *model, GdkDragContext *context, GtkTreePath *path,
- GtkSelectionData *selection, guint info);
-gboolean em_folder_tree_model_drag_data_delete (EMFolderTreeModel *model, GtkTreePath *path);
-void em_folder_tree_model_set_drag_drop_types (EMFolderTreeModel *model, GtkWidget *widget);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 17080668d8..c095d5be69 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -88,11 +88,40 @@ enum {
LAST_SIGNAL
};
+/* Drag & Drop types */
+enum DndDragType {
+ DND_DRAG_TYPE_FOLDER, /* drag an evo folder */
+ DND_DRAG_TYPE_TEXT_URI_LIST, /* drag to an mbox file */
+ NUM_DRAG_TYPES
+};
+
+enum DndDropType {
+ DND_DROP_TYPE_UID_LIST, /* drop a list of message uids */
+ DND_DROP_TYPE_FOLDER, /* drop an evo folder */
+ DND_DROP_TYPE_MESSAGE_RFC822, /* drop a message/rfc822 stream */
+ DND_DROP_TYPE_TEXT_URI_LIST, /* drop an mbox file */
+ NUM_DROP_TYPES
+};
+
+static GtkTargetEntry drag_types[] = {
+ { "x-folder", 0, DND_DRAG_TYPE_FOLDER },
+ { "text/uri-list", 0, DND_DRAG_TYPE_TEXT_URI_LIST },
+};
+
+static GtkTargetEntry drop_types[] = {
+ { "x-uid-list" , 0, DND_DROP_TYPE_UID_LIST },
+ { "x-folder", 0, DND_DROP_TYPE_FOLDER },
+ { "message/rfc822", 0, DND_DROP_TYPE_MESSAGE_RFC822 },
+ { "text/uri-list", 0, DND_DROP_TYPE_TEXT_URI_LIST },
+};
+
+static GdkAtom drag_atoms[NUM_DRAG_TYPES];
+static GdkAtom drop_atoms[NUM_DROP_TYPES];
+
static guint signals[LAST_SIGNAL] = { 0 };
extern CamelSession *session;
-
static void em_folder_tree_class_init (EMFolderTreeClass *klass);
static void em_folder_tree_init (EMFolderTree *emft);
static void em_folder_tree_destroy (GtkObject *obj);
@@ -112,7 +141,6 @@ struct _emft_selection_data {
gboolean set;
};
-
static GtkVBoxClass *parent_class = NULL;
GType
@@ -162,7 +190,6 @@ em_folder_tree_class_init (EMFolderTreeClass *klass)
G_TYPE_STRING);
}
-
static gboolean
subdirs_contain_unread (GtkTreeModel *model, GtkTreeIter *root)
{
@@ -321,7 +348,6 @@ em_folder_tree_destroy (GtkObject *obj)
GTK_OBJECT_CLASS (parent_class)->destroy (obj);
}
-
static GtkTreeView *
folder_tree_new (EMFolderTreeModel *model)
{
@@ -381,7 +407,6 @@ em_folder_tree_construct (EMFolderTree *emft, EMFolderTreeModel *model)
gtk_box_pack_start ((GtkBox *) emft, scrolled, TRUE, TRUE, 0);
}
-
GtkWidget *
em_folder_tree_new (void)
{
@@ -395,7 +420,6 @@ em_folder_tree_new (void)
return (GtkWidget *) emft;
}
-
struct _gsbn {
struct _EMFolderTreeModelStoreInfo *si;
const char *name;
@@ -463,7 +487,6 @@ emft_expand_node (const char *key, gpointer value, EMFolderTree *emft)
gtk_tree_path_free (path);
}
-
static void
emft_loading_row_cb (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTreeIter *iter, EMFolderTree *emft)
{
@@ -490,7 +513,6 @@ emft_loading_row_cb (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTreeIt
g_free (key);
}
-
GtkWidget *
em_folder_tree_new_with_model (EMFolderTreeModel *model)
{
@@ -508,7 +530,6 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model)
return (GtkWidget *) emft;
}
-
static void
tree_drag_begin (GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
{
@@ -530,43 +551,540 @@ tree_drag_begin (GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
}
static void
-tree_drag_data_delete (GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
+tree_drag_data_delete(GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv = emft->priv;
- GtkTreePath *path;
+ GtkTreePath *src_path;
+ const char *full_name;
+ gboolean is_store;
+ CamelStore *store;
+ CamelException ex;
+ GtkTreeIter iter;
+ char *path;
- if (!priv->drag_row || (path = gtk_tree_row_reference_get_path (priv->drag_row)))
+ if (!priv->drag_row || (src_path = gtk_tree_row_reference_get_path (priv->drag_row)))
return;
- em_folder_tree_model_drag_data_delete (priv->model, path);
- gtk_tree_path_free (path);
+ if (!gtk_tree_model_get_iter((GtkTreeModel *)priv->model, &iter, src_path))
+ goto fail;
+
+ gtk_tree_model_get((GtkTreeModel *)priv->model, &iter,
+ COL_POINTER_CAMEL_STORE, &store,
+ COL_STRING_FOLDER_PATH, &path,
+ COL_BOOL_IS_STORE, &is_store, -1);
+
+ if (is_store)
+ goto fail;
+
+ full_name = path[0] == '/' ? path + 1 : path;
+
+ camel_exception_init(&ex);
+ camel_store_delete_folder(store, full_name, &ex);
+ if (camel_exception_is_set(&ex))
+ camel_exception_clear(&ex);
+fail:
+ gtk_tree_path_free(src_path);
}
static void
-tree_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection, guint info, guint time, EMFolderTree *emft)
+tree_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection, guint info, guint time, EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv = emft->priv;
- GtkTreePath *path;
+ GtkTreePath *src_path;
+ const char *full_name;
+ CamelFolder *folder;
+ CamelStore *store;
+ CamelException ex;
+ GtkTreeIter iter;
+ char *path, *uri;
- if (!priv->drag_row || !(path = gtk_tree_row_reference_get_path (priv->drag_row)))
+ if (!priv->drag_row || !(src_path = gtk_tree_row_reference_get_path(priv->drag_row)))
return;
- em_folder_tree_model_drag_data_get (priv->model, context, path, selection, info);
- gtk_tree_path_free (path);
+ if (!gtk_tree_model_get_iter((GtkTreeModel *)priv->model, &iter, src_path))
+ goto fail;
+
+ gtk_tree_model_get((GtkTreeModel *)priv->model, &iter,
+ COL_POINTER_CAMEL_STORE, &store,
+ COL_STRING_FOLDER_PATH, &path,
+ COL_STRING_URI, &uri, -1);
+
+ /* make sure user isn't trying to drag on a placeholder row */
+ if (path == NULL)
+ goto fail;
+
+ full_name = path[0] == '/' ? path + 1 : path;
+
+ camel_exception_init(&ex);
+
+ switch (info) {
+ case DND_DRAG_TYPE_FOLDER:
+ /* dragging to a new location in the folder tree */
+ printf ("dragging uri: %s\n", uri);
+ gtk_selection_data_set(selection, drag_atoms[info], 8, uri, strlen (uri) + 1);
+ break;
+ case DND_DRAG_TYPE_TEXT_URI_LIST:
+ /* dragging to nautilus or something, probably */
+ if ((folder = camel_store_get_folder(store, full_name, 0, &ex))) {
+ GPtrArray *uids = camel_folder_get_uids(folder);
+
+ em_utils_selection_set_urilist(selection, folder, uids);
+ camel_folder_free_uids(folder, uids);
+ camel_object_unref(folder);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ if (camel_exception_is_set(&ex))
+ camel_exception_clear(&ex);
+fail:
+ gtk_tree_path_free(src_path);
+}
+
+/* Drop handling */
+struct _DragDataReceivedAsync {
+ struct _mail_msg msg;
+
+ /* input data */
+ GdkDragContext *context;
+
+ union {
+ CamelStreamMem *rfc822;
+ char *folder;
+ char **urilist;
+ struct {
+ char *uri;
+ GPtrArray *uids;
+ } uidlist;
+ } selection;
+
+ CamelStore *store;
+ char *full_name;
+ gboolean move;
+ guint info;
+
+ /* output data */
+ gboolean moved;
+};
+
+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
-tree_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection,
- guint info, guint time, EMFolderTree *emft)
+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));
+
+ if (!(src = mail_tool_uri_to_folder(m->selection.folder, 0, &m->msg.ex)))
+ return;
+
+ /* handles dropping to the root properly */
+ if (m->full_name[0])
+ new_name = g_strdup_printf("%s/%s", m->full_name, src->name);
+ else
+ new_name = g_strdup(src->name);
+
+ if (src->parent_store == m->store && m->move) {
+ /* simple case, rename */
+ camel_store_rename_folder(m->store, src->full_name, new_name, &m->msg.ex);
+ m->moved = !camel_exception_is_set (&m->msg.ex);
+ } else {
+ CamelFolder *dest;
+
+ /* FIXME: should check we're not coming from a vfolder, otherwise bad stuff could happen */
+
+ /* copy the folder to the new location */
+ if ((dest = camel_store_get_folder(m->store, new_name, CAMEL_STORE_FOLDER_CREATE, &m->msg.ex))) {
+ GPtrArray *uids;
+
+ uids = camel_folder_get_uids (src);
+ camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, &m->msg.ex);
+ camel_folder_free_uids (src, uids);
+
+ camel_object_unref (dest);
+ }
+ }
+
+ g_free(new_name);
+ 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 void
+emft_drop_async_drop (struct _mail_msg *mm)
+{
+ struct _DragDataReceivedAsync *m = (struct _DragDataReceivedAsync *) mm;
+ CamelFolder *folder;
+
+ /* for types other than folder, we can't drop to the root path */
+ if (m->info == DND_DROP_TYPE_FOLDER) {
+ /* copy or move (aka rename) a folder */
+ emft_drop_folder(m);
+ } else if (m->full_name[0] == 0) {
+ camel_exception_set (&mm->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot drop message(s) into toplevel store"));
+ } else if ((folder = camel_store_get_folder (m->store, m->full_name, 0, &mm->ex))) {
+ switch (m->info) {
+ case DND_DROP_TYPE_UID_LIST:
+ /* import a list of uids from another evo folder */
+ emft_drop_uid_list(m, folder);
+ break;
+ case DND_DROP_TYPE_MESSAGE_RFC822:
+ /* import a message/rfc822 stream */
+ emft_drop_message_rfc822(m, folder);
+ break;
+ case DND_DROP_TYPE_TEXT_URI_LIST:
+ /* import an mbox, maildir, or mh folder? */
+ emft_drop_text_uri_list(m, folder);
+ break;
+ default:
+ abort();
+ }
+ camel_object_unref(folder);
+ }
+}
+
+static void
+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;
+
+ gtk_drag_finish (m->context, success, delete, GDK_CURRENT_TIME);
+}
+
+static void
+emft_drop_async_free (struct _mail_msg *mm)
+{
+ struct _DragDataReceivedAsync *m = (struct _DragDataReceivedAsync *) mm;
+
+ g_object_unref(m->context);
+ 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();
+ }
+}
+
+static struct _mail_msg_op emft_drop_async_op = {
+ NULL,
+ emft_drop_async_drop,
+ emft_drop_async_done,
+ emft_drop_async_free,
+};
+
+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;
GtkTreeViewDropPosition pos;
- GtkTreePath *path;
+ GtkTreePath *dest_path;
+ struct _DragDataReceivedAsync *m;
+ const char *full_name;
+ CamelStore *store;
+ GtkTreeIter iter;
+ char *path, *tmp;
+ int i;
+
+ if (!gtk_tree_view_get_dest_row_at_pos (priv->treeview, x, y, &dest_path, &pos))
+ return;
+
+ /*em_folder_tree_model_drag_data_received (priv->model, context, path, selection, info);*/
+
+ /* this means we are receiving no data */
+ if (!selection->data || selection->length == -1) {
+ gtk_drag_finish(context, FALSE, FALSE, GDK_CURRENT_TIME);
+ return;
+ }
- if (!gtk_tree_view_get_dest_row_at_pos (priv->treeview, x, y, &path, &pos))
+ if (!gtk_tree_model_get_iter((GtkTreeModel *)priv->model, &iter, dest_path)) {
+ gtk_drag_finish(context, FALSE, FALSE, GDK_CURRENT_TIME);
return;
+ }
+
+ gtk_tree_model_get((GtkTreeModel *)priv->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) {
+ gtk_drag_finish (context, FALSE, FALSE, GDK_CURRENT_TIME);
+ return;
+ }
+
+ full_name = path[0] == '/' ? path + 1 : path;
+
+ m = mail_msg_new (&emft_drop_async_op, NULL, sizeof (struct _DragDataReceivedAsync));
+ m->context = context;
+ g_object_ref(context);
+ m->store = store;
+ camel_object_ref(store);
+ m->full_name = g_strdup (full_name);
+ m->move = context->action == GDK_ACTION_MOVE;
+ 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();
+ }
+
+ e_thread_put (mail_thread_new, (EMsg *) m);
+}
+
+static GdkAtom
+emft_drop_target(EMFolderTree *emft, GdkDragContext *context, GtkTreePath *path)
+{
+ struct _EMFolderTreePrivate *p = emft->priv;
+ gboolean is_store;
+ GtkTreeIter iter;
+ GList *targets;
+ char *uri, *src_uri = NULL;
+
+ /* This is a bit of a mess, but should handle all the cases properly */
+
+ if (!gtk_tree_model_get_iter((GtkTreeModel *)p->model, &iter, path))
+ return GDK_NONE;
+
+ gtk_tree_model_get((GtkTreeModel *)p->model, &iter, COL_BOOL_IS_STORE, &is_store, COL_STRING_URI, &uri, -1);
+
+ if (p->drag_row) {
+ GtkTreePath *src_path = gtk_tree_row_reference_get_path(p->drag_row);
+
+ if (src_path) {
+ if (gtk_tree_model_get_iter((GtkTreeModel *)p->model, &iter, src_path))
+ gtk_tree_model_get((GtkTreeModel *)p->model, &iter,
+ COL_STRING_URI, &src_uri, -1);
+
+ /* can't dnd onto itself or below itself - bad things happen,
+ no point dragging to where we were either */
+ if (gtk_tree_path_compare(path, src_path) == 0
+ || gtk_tree_path_is_descendant(path, src_path)
+ || (gtk_tree_path_is_ancestor(path, src_path)
+ && gtk_tree_path_get_depth(path) == gtk_tree_path_get_depth(src_path)-1)) {
+ gtk_tree_path_free(src_path);
+ return GDK_NONE;
+ }
+
+ gtk_tree_path_free(src_path);
+ }
+ }
- em_folder_tree_model_drag_data_received (priv->model, context, path, selection, info);
+ targets = context->targets;
+
+ /* Check for special sources, and vfolder stuff */
+ if (src_uri) {
+ CamelURL *url;
+ char *path;
+
+ /* FIXME: this is a total hack, but i think all we can do at present */
+ /* Check for dragging from spethal folders which can't be moved/copied */
+ url = camel_url_new(src_uri, NULL);
+ path = url->fragment?url->fragment:url->path;
+ printf("checking url src path '%s'\n", path);
+ if (path
+ && (strcmp(path, CAMEL_VTRASH_NAME) == 0
+ || strcmp(path, CAMEL_VJUNK_NAME) == 0
+ || strcmp(path, CAMEL_UNMATCHED_NAME) == 0
+ /* Dont allow drag from maildir 'inbox' */
+ || strcmp(path, ".") == 0)) {
+ camel_url_free(url);
+ return GDK_NONE;
+ }
+ camel_url_free(url);
+
+ if (uri) {
+ /* Check for dragging folders into spethal folders */
+ url = camel_url_new(uri, NULL);
+ path = url->fragment?url->fragment:url->path;
+ printf("checking url dest path '%s'\n", path);
+ if (path && path[0]
+ && (strcmp(path, CAMEL_VTRASH_NAME) == 0
+ || strcmp(path, CAMEL_VJUNK_NAME) == 0
+ || strcmp(path, CAMEL_UNMATCHED_NAME) == 0)) {
+ camel_url_free(url);
+ return GDK_NONE;
+ }
+ camel_url_free(url);
+ }
+
+ if (strncmp(src_uri, "vfolder:", 8) == 0) {
+ /* TODO: not sure if this is legal, but it works, force move only for vfolders */
+ context->suggested_action = GDK_ACTION_MOVE;
+
+ if (uri && strncmp(uri, "vfolder:", 8) == 0) {
+ GdkAtom xfolder;
+
+ xfolder = drop_atoms[DND_DROP_TYPE_FOLDER];
+ while (targets != NULL) {
+ if (targets->data == (gpointer) xfolder)
+ return xfolder;
+
+ targets = targets->next;
+ }
+ }
+
+ return GDK_NONE;
+ }
+ }
+
+ /* can't drag anything but a vfolder into a vfolder */
+ if (uri && strncmp(uri, "vfolder:", 8) == 0)
+ return GDK_NONE;
+
+ /* Now we either have a store or a normal folder */
+
+ if (is_store) {
+ GdkAtom xfolder;
+
+ xfolder = drop_atoms[DND_DROP_TYPE_FOLDER];
+ while (targets != NULL) {
+ if (targets->data == (gpointer) xfolder)
+ return xfolder;
+
+ targets = targets->next;
+ }
+ } else {
+ int i;
+
+ while (targets != NULL) {
+ for (i = 0; i < NUM_DROP_TYPES; i++) {
+ if (targets->data == (gpointer) drop_atoms[i])
+ return drop_atoms[i];
+ }
+
+ targets = targets->next;
+ }
+ }
+
+ return GDK_NONE;
}
static gboolean
@@ -581,7 +1099,7 @@ tree_drag_drop (GtkWidget *widget, GdkDragContext *context, int x, int y, guint
if (!gtk_tree_view_get_path_at_pos (priv->treeview, x, y, &path, &column, &cell_x, &cell_y))
return FALSE;
- target = em_folder_tree_model_row_drop_target (priv->model, context, path);
+ target = emft_drop_target(emft, context, path);
gtk_tree_path_free (path);
if (target == GDK_NONE)
return FALSE;
@@ -598,14 +1116,14 @@ tree_drag_end (GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
gtk_tree_row_reference_free (priv->drag_row);
priv->drag_row = NULL;
}
-
+
/* FIXME: undo anything done in drag-begin */
}
static void
tree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, EMFolderTree *emft)
{
- /* FIXME: unhighlight target row? */
+ gtk_tree_view_set_drag_dest_row(emft->priv->treeview, NULL, GTK_TREE_VIEW_DROP_BEFORE);
}
static gboolean
@@ -614,32 +1132,63 @@ tree_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, guin
struct _EMFolderTreePrivate *priv = emft->priv;
GtkTreeViewDropPosition pos;
GtkTreePath *path;
- GdkDragAction action;
+ GdkDragAction action = 0;
+ GdkAtom target;
+ int i;
- if (!gtk_tree_view_get_dest_row_at_pos (priv->treeview, x, y, &path, &pos))
+ if (!gtk_tree_view_get_dest_row_at_pos(priv->treeview, x, y, &path, &pos))
return FALSE;
+
+ 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_AFTER);
+ break;
+ default:
+ gtk_tree_view_set_drag_dest_row(priv->treeview, path, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
+ action = context->suggested_action;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ gtk_tree_path_free(path);
- /* FIXME: highlight target row? */
-
- action = em_folder_tree_model_row_drop_possible (priv->model, context, path);
- gtk_tree_path_free (path);
-
- gdk_drag_status (context, action, time);
+ gdk_drag_status(context, action, time);
- return action;
+ return action != 0;
}
-
void
em_folder_tree_enable_drag_and_drop (EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv;
+ int i;
+ static int setup;
g_return_if_fail (EM_IS_FOLDER_TREE (emft));
priv = emft->priv;
+ if (!setup) {
+ for (i=0; i<NUM_DRAG_TYPES; i++)
+ drag_atoms[i] = gdk_atom_intern(drag_types[i].target, FALSE);
- em_folder_tree_model_set_drag_drop_types (priv->model, (GtkWidget *) priv->treeview);
+ for (i=0; i<NUM_DROP_TYPES; i++)
+ drop_atoms[i] = gdk_atom_intern(drop_types[i].target, FALSE);
+
+ 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);
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);
@@ -651,7 +1200,6 @@ em_folder_tree_enable_drag_and_drop (EMFolderTree *emft)
g_signal_connect (priv->treeview, "drag-motion", G_CALLBACK (tree_drag_motion), emft);
}
-
void
em_folder_tree_set_multiselect (EMFolderTree *tree, gboolean mode)
{