diff options
Diffstat (limited to 'mail/em-folder-tree.c')
-rw-r--r-- | mail/em-folder-tree.c | 171 |
1 files changed, 129 insertions, 42 deletions
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index f86c6ef94c..1ce14f763c 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -956,30 +956,76 @@ tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y e_thread_put (mail_thread_new, (EMsg *) m); } +static gboolean +is_special_local_folder (const char *name) +{ + return (!strcmp (name, "Drafts") || !strcmp (name, "Inbox") || !strcmp (name, "Outbox") || !strcmp (name, "Sent")); +} + static GdkAtom emft_drop_target(EMFolderTree *emft, GdkDragContext *context, GtkTreePath *path) { struct _EMFolderTreePrivate *p = emft->priv; + char *uri, *folder_path, *src_uri = NULL; + CamelStore *local, *sstore, *dstore; 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); - + gtk_tree_model_get((GtkTreeModel *)p->model, &iter, COL_BOOL_IS_STORE, &is_store, + COL_STRING_FOLDER_PATH, &folder_path, + COL_POINTER_CAMEL_STORE, &dstore, + COL_STRING_URI, &uri, -1); + + local = mail_component_peek_local_store (NULL); + + targets = context->targets; + + /* Check for special destinations */ + if (uri && folder_path) { + folder_path = folder_path[0] == '/' ? folder_path + 1 : folder_path; + +#if 0 + /* only allow copying/moving folders (not messages) into the local Outbox */ + if (dstore == local && !strcmp (folder_path, "Outbox")) { + 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; + } +#endif + + /* don't allow copying/moving into the UNMATCHED vfolder */ + if (!strncmp (uri, "vfolder:", 8) && !strcmp (folder_path, CAMEL_UNMATCHED_NAME)) + return GDK_NONE; + + /* don't allow copying/moving into a vTrash/vJunk folder */ + if (!strcmp (folder_path, CAMEL_VTRASH_NAME) + || !strcmp (folder_path, CAMEL_VJUNK_NAME)) + return GDK_NONE; + } + 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_POINTER_CAMEL_STORE, &sstore, 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 @@ -994,42 +1040,53 @@ emft_drop_target(EMFolderTree *emft, GdkDragContext *context, GtkTreePath *path) } } - 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 */ + /* Check for dragging from special folders which can't be moved/copied */ url = camel_url_new(src_uri, NULL); path = url->fragment?url->fragment:url->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; - if (path && path[0] - && (strcmp(path, CAMEL_VTRASH_NAME) == 0 - || strcmp(path, CAMEL_VJUNK_NAME) == 0 - || strcmp(path, CAMEL_UNMATCHED_NAME) == 0)) { + if (path && path[0]) { + /* don't allow moving any of the the local special folders */ + if (sstore == local && is_special_local_folder (path)) { + GdkAtom xfolder; + + camel_url_free (url); + + /* TODO: not sure if this is legal, but it works, force copy for special local folders */ + context->suggested_action = GDK_ACTION_COPY; + xfolder = drop_atoms[DND_DROP_TYPE_FOLDER]; + while (targets != NULL) { + if (targets->data == (gpointer) xfolder) + return xfolder; + + targets = targets->next; + } + + return GDK_NONE; + } + + /* don't allow copying/moving of the UNMATCHED vfolder */ + if (!strcmp (url->protocol, "vfolder") && !strcmp (path, CAMEL_UNMATCHED_NAME)) { + camel_url_free (url); + return GDK_NONE; + } + + /* don't allow copying/moving of any vTrash/vJunk folder nor maildir 'inbox' */ + if (strcmp(path, CAMEL_VTRASH_NAME) == 0 + || strcmp(path, CAMEL_VJUNK_NAME) == 0 + /* Dont allow drag from maildir 'inbox' */ + || strcmp(path, ".") == 0) { camel_url_free(url); return GDK_NONE; } - camel_url_free(url); } - + camel_url_free(url); + + /* vFolders can only be dropped into other vFolders */ 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; @@ -1041,7 +1098,7 @@ emft_drop_target(EMFolderTree *emft, GdkDragContext *context, GtkTreePath *path) while (targets != NULL) { if (targets->data == (gpointer) xfolder) return xfolder; - + targets = targets->next; } } @@ -1055,7 +1112,7 @@ emft_drop_target(EMFolderTree *emft, GdkDragContext *context, GtkTreePath *path) return GDK_NONE; /* Now we either have a store or a normal folder */ - + if (is_store) { GdkAtom xfolder; @@ -1133,7 +1190,7 @@ tree_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, guin 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++) { @@ -1674,6 +1731,7 @@ emft_popup_copy_folder_selected (const char *uri, void *data) struct _EMFolderTreePrivate *priv; CamelStore *fromstore, *tostore; char *tobase, *frombase; + GtkWindow *parent; CamelException ex; GtkWidget *dialog; CamelURL *url; @@ -1685,13 +1743,19 @@ emft_popup_copy_folder_selected (const char *uri, void *data) priv = cfd->emft->priv; - d(printf ("copying folder '%s' to '%s'\n", priv->selected_path, uri)); + d(printf ("%sing folder '%s' to '%s'\n", cfd->delete ? "move" : "copy", priv->selected_path, uri)); camel_exception_init (&ex); if (!(fromstore = camel_session_get_store (session, priv->selected_uri, &ex))) goto exception; frombase = priv->selected_path + 1; + if (fromstore == mail_component_peek_local_store (NULL) && is_special_local_folder (frombase)) { + if (cfd->delete) + camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot move folder `%s': illegal operation"), frombase); + camel_object_unref (fromstore); + goto exception; + } if (!(tostore = camel_session_get_store (session, uri, &ex))) { camel_object_unref (fromstore); @@ -1715,7 +1779,8 @@ emft_popup_copy_folder_selected (const char *uri, void *data) exception: - dialog = gtk_message_dialog_new ((GtkWindow *) cfd->emft, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + parent = (GtkWindow *) gtk_widget_get_ancestor ((GtkWidget *) cfd->emft, GTK_TYPE_WINDOW); + dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("%s"), ex.desc); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); camel_exception_clear (&ex); @@ -1757,6 +1822,7 @@ em_folder_tree_create_folder (EMFolderTree *emft, const char *path, const char * struct _EMFolderTreeModelStoreInfo *si; const char *parent, *full_name; char *name, *namebuf = NULL; + GtkWindow *window; GtkWidget *dialog; CamelStore *store; CamelException ex; @@ -1802,7 +1868,8 @@ em_folder_tree_create_folder (EMFolderTree *emft, const char *path, const char * exception: - dialog = gtk_message_dialog_new ((GtkWindow *) emft, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + window = (GtkWindow *) gtk_widget_get_ancestor ((GtkWidget *) emft, GTK_TYPE_WINDOW); + dialog = gtk_message_dialog_new (window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("%s"), ex.desc); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); camel_exception_clear (&ex); @@ -1967,19 +2034,29 @@ emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) { struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; + CamelStore *local, *store; GtkTreeModel *model; GtkTreeIter iter; GtkWidget *dialog; + const char *full_name; char *title, *path; selection = gtk_tree_view_get_selection (priv->treeview); emft_selection_get_selected (selection, &model, &iter); - gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, -1); + gtk_tree_model_get (model, &iter, COL_POINTER_CAMEL_STORE, &store, COL_STRING_FOLDER_PATH, &path, -1); + + local = mail_component_peek_local_store (NULL); + + full_name = path[0] == '/' ? path + 1 : path; + if (store == local && is_special_local_folder (full_name)) { + e_notice (NULL, GTK_MESSAGE_ERROR, _("Cannot delete local %s folder."), full_name); + return; + } dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Really delete folder \"%s\" and all of its subfolders?"), - path); + full_name); gtk_dialog_add_button ((GtkDialog *) dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button ((GtkDialog *) dialog, GTK_STOCK_DELETE, GTK_RESPONSE_OK); @@ -1988,7 +2065,7 @@ emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) gtk_container_set_border_width ((GtkContainer *) dialog, 6); gtk_box_set_spacing ((GtkBox *) ((GtkDialog *) dialog)->vbox, 6); - title = g_strdup_printf (_("Delete \"%s\""), path); + title = g_strdup_printf (_("Delete \"%s\""), full_name); gtk_window_set_title ((GtkWindow *) dialog, title); g_free (title); @@ -2003,12 +2080,14 @@ emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) char *prompt, *folder_path, *name, *new_name, *uri; GtkTreeSelection *selection; const char *full_name, *p; + CamelStore *local, *store; gboolean done = FALSE; GtkTreeModel *model; - CamelStore *store; GtkTreeIter iter; size_t base_len; + local = mail_component_peek_local_store (NULL); + selection = gtk_tree_view_get_selection (priv->treeview); emft_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &folder_path, @@ -2017,6 +2096,13 @@ emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) COL_STRING_URI, &uri, -1); full_name = folder_path[0] == '/' ? folder_path + 1 : folder_path; + + /* don't allow user to rename one of the special local folders */ + if (store == local && is_special_local_folder (full_name)) { + e_notice (NULL, GTK_MESSAGE_ERROR, _("Cannot rename local %s folder."), full_name); + return; + } + if ((p = strrchr (full_name, '/'))) base_len = (size_t) (p - full_name); else @@ -2116,6 +2202,7 @@ static EMPopupItem emft_popup_menu[] = { static gboolean emft_tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *emft) { + /* FIXME: need to disable Rename/Move for Outbox and possibly other special folders */ struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkTreeModel *model; @@ -2133,7 +2220,7 @@ emft_tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree /* handle right-click by opening a context menu */ emp = em_popup_new ("com.ximian.mail.storageset.popup.select"); - + /* FIXME: we really need the folderinfo to build a proper menu */ selection = gtk_tree_view_get_selection (priv->treeview); emft_selection_get_selected (selection, &model, &iter); |