From: Sergio Villar Senin Date: Wed, 19 Sep 2007 15:39:37 +0000 (+0000) Subject: * Renamed one method in modest UI actions X-Git-Tag: git_migration_finished~2335 X-Git-Url: http://git.maemo.org/git/?p=modest;a=commitdiff_plain;h=aa217bb73f75e470e94184a592701176623bcc1f * Renamed one method in modest UI actions * Added modest-dnd.c with some helper functions for drag&drop * Fixes NB#62404, drag&drop of multiple headers at a time is now possible pmo-trunk-r3354 --- diff --git a/src/modest-ui-actions.c b/src/modest-ui-actions.c index 2e78faa..77c1a42 100644 --- a/src/modest-ui-actions.c +++ b/src/modest-ui-actions.c @@ -3141,10 +3141,11 @@ modest_ui_actions_on_paste (GtkAction *action, gint response = 0; /* Ask for user confirmation */ - response = msgs_move_to_confirmation (GTK_WINDOW (window), - TNY_FOLDER (folder_store), - delete, - data); + response = + modest_ui_actions_msgs_move_to_confirmation (GTK_WINDOW (window), + TNY_FOLDER (folder_store), + delete, + data); if (response == GTK_RESPONSE_OK) { /* Launch notification */ @@ -3828,10 +3829,10 @@ has_retrieved_msgs (TnyList *list) * drag_and_drop_from_header_view (for d&d in modest_folder_view.c) */ gint -msgs_move_to_confirmation (GtkWindow *win, - TnyFolder *dest_folder, - gboolean delete, - TnyList *headers) +modest_ui_actions_msgs_move_to_confirmation (GtkWindow *win, + TnyFolder *dest_folder, + gboolean delete, + TnyList *headers) { gint response = GTK_RESPONSE_OK; diff --git a/src/modest-ui-actions.h b/src/modest-ui-actions.h index f63bdc2..0254434 100644 --- a/src/modest-ui-actions.h +++ b/src/modest-ui-actions.h @@ -469,10 +469,10 @@ void modest_do_messages_delete (TnyList *headers, ModestWindow *win); */ gboolean modest_run_account_setup_wizard (ModestWindow *win); -gint msgs_move_to_confirmation (GtkWindow *win, - TnyFolder *dest_folder, - gboolean delete, - TnyList *headers); +gint modest_ui_actions_msgs_move_to_confirmation (GtkWindow *win, + TnyFolder *dest_folder, + gboolean delete, + TnyList *headers); /* * modest_ui_actions_on_send_queue_error_happened: diff --git a/src/widgets/Makefile.am b/src/widgets/Makefile.am index b5a1af3..84ea7cd 100644 --- a/src/widgets/Makefile.am +++ b/src/widgets/Makefile.am @@ -25,6 +25,8 @@ libmodest_widgets_la_SOURCES= \ modest-attachments-view.h \ modest-combo-box.c \ modest-combo-box.h \ + modest-dnd.c \ + modest-dnd.h \ modest-folder-view.c \ modest-folder-view.h \ modest-global-settings-dialog.c \ diff --git a/src/widgets/modest-dnd.c b/src/widgets/modest-dnd.c new file mode 100644 index 0000000..a718366 --- /dev/null +++ b/src/widgets/modest-dnd.c @@ -0,0 +1,95 @@ +/* Copyright (c) 2006, Nokia Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Nokia Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "modest-dnd.h" +#include +#include + +GdkAtom tree_path_as_string_list_atom; + +static void +init_atom (void) +{ + if (!tree_path_as_string_list_atom) + tree_path_as_string_list_atom = + gdk_atom_intern_static_string (GTK_TREE_PATH_AS_STRING_LIST); +} + + +void +modest_dnd_selection_data_set_paths (GtkSelectionData *selection_data, + GList *selected_rows) +{ + init_atom (); + + if (selection_data->target == tree_path_as_string_list_atom) { + GString *list; + gint i; + gchar *result; + GList *row; + + row = selected_rows; + list = g_string_new (NULL); + + for (i = 0; idata)); + g_string_append (list, "\n"); + row = g_list_next (row); + } + /* Do not include the delimiter in the last one */ + g_string_append (list, gtk_tree_path_to_string (row->data)); + + result = g_strdup (list->str); + g_string_free (list, TRUE); + + if (result) { + gtk_selection_data_set (selection_data, + tree_path_as_string_list_atom, + 8, (guchar *)result, + strlen (result)); + + g_free (result); + } + } +} + +gchar** +modest_dnd_selection_data_get_paths (GtkSelectionData *selection_data) +{ + gchar **result = NULL; + + init_atom (); + + if (selection_data->length >= 0 && + selection_data->type == tree_path_as_string_list_atom) { + + result = g_strsplit (selection_data->data, "\n", 0); + } + return result; +} diff --git a/src/widgets/modest-dnd.h b/src/widgets/modest-dnd.h index 6c1723f..1a7a714 100644 --- a/src/widgets/modest-dnd.h +++ b/src/widgets/modest-dnd.h @@ -30,16 +30,40 @@ #ifndef __MODEST_DND_H__ #define __MODEST_DND_H__ -G_BEGIN_DECLS +#include +#include -#define ROW_REF_DATA_NAME "row-ref" +extern GdkAtom tree_path_as_string_list_atom; + +#define GTK_TREE_PATH_AS_STRING_LIST "text/tree-path-as-string-list" enum { - MODEST_FOLDER_ROW, - MODEST_HEADER_ROW, - MODEST_MSG + MODEST_FOLDER_ROW, + MODEST_HEADER_ROW }; -G_END_DECLS +/** + * modest_dnd_selection_data_set_paths: + * @selection_data: + * @selected_rows: + * + * This function sets a list of gtk_tree_path's represented as strings + * as the data of a #GtkSelectionData object that will be used during + * drag and drop + **/ +void modest_dnd_selection_data_set_paths (GtkSelectionData *selection_data, + GList *selected_rows); + + +/** + * modest_dnd_selection_data_get_paths: + * @selection_data: + * + * This function gets a list of gtk_tree_path's represented as strings + * from a #GtkSelectionData object used during drag and drop + * + * Returns: the list of gtk_tree_paths as strings or NULL + **/ +gchar** modest_dnd_selection_data_get_paths (GtkSelectionData *selection_data); #endif /* __MODEST_DND_H__ */ diff --git a/src/widgets/modest-folder-view.c b/src/widgets/modest-folder-view.c index dca748b..20819f7 100644 --- a/src/widgets/modest-folder-view.c +++ b/src/widgets/modest-folder-view.c @@ -52,10 +52,17 @@ #include #include #include "modest-folder-view.h" -#include #include #include #include +#include "modest-dnd.h" + +/* Folder view drag types */ +const GtkTargetEntry folder_view_drag_types[] = +{ + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW }, + { GTK_TREE_PATH_AS_STRING_LIST, GTK_TARGET_SAME_APP, MODEST_HEADER_ROW } +}; /* 'private'/'protected' functions */ static void modest_folder_view_class_init (ModestFolderViewClass *klass); @@ -1465,7 +1472,6 @@ finish: /*****************************************************************************/ /* DRAG and DROP stuff */ /*****************************************************************************/ - /* * This function fills the #GtkSelectionData with the row and the * model that has been dragged. It's called when this widget is a @@ -1552,18 +1558,6 @@ tree_path_to_folder (GtkTreeModel *model, GtkTreePath *path) return folder; } -static void -show_banner_move_target_error () -{ - ModestWindow *main_window; - - main_window = modest_window_mgr_get_main_window( - modest_runtime_get_window_mgr()); - - modest_platform_information_banner(GTK_WIDGET(main_window), - NULL, _("mail_in_ui_folder_move_target_error")); -} - /* * This function is used by drag_data_received_cb to manage drag and * drop of a header, i.e, and drag from the header view to the folder @@ -1573,66 +1567,69 @@ static void drag_and_drop_from_header_view (GtkTreeModel *source_model, GtkTreeModel *dest_model, GtkTreePath *dest_row, + GtkSelectionData *selection_data, DndHelper *helper) { TnyList *headers = NULL; - TnyHeader *header = NULL; TnyFolder *folder = NULL; ModestMailOperation *mail_op = NULL; - GtkTreeIter source_iter; - ModestWindowMgr *mgr = NULL; /*no need for unref*/ - ModestWindow *main_win = NULL; /*no need for unref*/ - - g_return_if_fail (GTK_IS_TREE_MODEL(source_model)); - g_return_if_fail (GTK_IS_TREE_MODEL(dest_model)); - g_return_if_fail (dest_row); - g_return_if_fail (helper); - - /* Get header */ - gtk_tree_model_get_iter (source_model, &source_iter, helper->source_row); - gtk_tree_model_get (source_model, &source_iter, - TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, - &header, -1); - if (!TNY_IS_HEADER(header)) { - g_warning ("BUG: %s could not get a valid header", __FUNCTION__); - goto cleanup; - } - - /* Check if the selected message is in msg-view. If it is than - * do not enable drag&drop on that. */ + GtkTreeIter source_iter, dest_iter; + ModestWindowMgr *mgr = NULL; + ModestWindow *main_win = NULL; + gchar **uris, **tmp; + gint response; + + /* Build the list of headers */ mgr = modest_runtime_get_window_mgr (); - if (modest_window_mgr_find_registered_header(mgr, header, NULL)) - goto cleanup; + headers = tny_simple_list_new (); + uris = modest_dnd_selection_data_get_paths (selection_data); + tmp = uris; - /* Get Folder */ - folder = tree_path_to_folder (dest_model, dest_row); - if (!TNY_IS_FOLDER(folder)) { - g_warning ("BUG: %s could not get a valid folder", __FUNCTION__); - show_banner_move_target_error(); - goto cleanup; - } - if (modest_tny_folder_get_rules(folder) & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) { - g_debug ("folder rules: cannot write to that folder"); - goto cleanup; + while (*tmp != NULL) { + TnyHeader *header; + GtkTreePath *path; + + /* Get header */ + path = gtk_tree_path_new_from_string (*tmp); + gtk_tree_model_get_iter (source_model, &source_iter, path); + gtk_tree_model_get (source_model, &source_iter, + TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, + &header, -1); + + /* Do not enable d&d of headers already opened */ + if (!modest_window_mgr_find_registered_header(mgr, header, NULL)) + tny_list_append (headers, G_OBJECT (header)); + + /* Free and go on */ + gtk_tree_path_free (path); + g_object_unref (header); + tmp++; } - - headers = tny_simple_list_new (); - tny_list_append (headers, G_OBJECT (header)); + g_strfreev (uris); + + /* Get the target folder */ + gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row); + gtk_tree_model_get (dest_model, &dest_iter, + TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, + &folder, -1); + /* Ask for confirmation to move */ main_win = modest_window_mgr_get_main_window(mgr); - if(msgs_move_to_confirmation(GTK_WINDOW(main_win), folder, TRUE, headers) - == GTK_RESPONSE_CANCEL) + response = modest_ui_actions_msgs_move_to_confirmation (GTK_WINDOW(main_win), folder, + TRUE, headers); + if (response == GTK_RESPONSE_CANCEL) goto cleanup; - /* Transfer message */ + /* Transfer messages */ mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, NULL, modest_ui_actions_move_folder_error_handler, NULL); + modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op); - modest_mail_operation_xfer_msgs (mail_op, + modest_mail_operation_xfer_msgs (mail_op, headers, folder, helper->delete_source, @@ -1642,8 +1639,6 @@ drag_and_drop_from_header_view (GtkTreeModel *source_model, cleanup: if (G_IS_OBJECT(mail_op)) g_object_unref (G_OBJECT (mail_op)); - if (G_IS_OBJECT(header)) - g_object_unref (G_OBJECT (header)); if (G_IS_OBJECT(folder)) g_object_unref (G_OBJECT (folder)); if (G_IS_OBJECT(headers)) @@ -1791,17 +1786,8 @@ on_drag_data_received (GtkWidget *widget, if (selection_data == NULL || selection_data->length < 0) gtk_drag_finish (context, success, FALSE, time); - /* Get the models */ - gtk_tree_get_row_drag_data (selection_data, - &source_model, - &source_row); - /* Select the destination model */ - if (source_widget == widget) { - dest_model = source_model; - } else { - dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - } + dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); /* Get the path to the destination row. Can not call gtk_tree_view_get_drag_dest_row() because the source row @@ -1810,35 +1796,43 @@ on_drag_data_received (GtkWidget *widget, &dest_row, &pos); /* Only allow drops IN other rows */ - if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER) + if (!dest_row || + pos == GTK_TREE_VIEW_DROP_BEFORE || + pos == GTK_TREE_VIEW_DROP_AFTER) gtk_drag_finish (context, success, FALSE, time); /* Create the helper */ helper = g_slice_new0 (DndHelper); helper->delete_source = delete_source; - helper->source_row = gtk_tree_path_copy (source_row); helper->context = context; helper->time = time; /* Drags from the header view */ if (source_widget != widget) { + source_model = gtk_tree_view_get_model (GTK_TREE_VIEW (source_widget)); drag_and_drop_from_header_view (source_model, dest_model, dest_row, + selection_data, helper); } else { - + /* Get the source model and row */ + gtk_tree_get_row_drag_data (selection_data, + &source_model, + &source_row); + helper->source_row = gtk_tree_path_copy (source_row); drag_and_drop_from_folder_view (source_model, dest_model, dest_row, selection_data, helper); + + gtk_tree_path_free (source_row); } /* Frees */ - gtk_tree_path_free (source_row); gtk_tree_path_free (dest_row); } @@ -1926,9 +1920,11 @@ on_drag_motion (GtkWidget *widget, { GtkTreeViewDropPosition pos; GtkTreePath *dest_row; + GtkTreeModel *dest_model; ModestFolderViewPrivate *priv; GdkDragAction suggested_action; gboolean valid_location = FALSE; + TnyFolder *folder; priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget); @@ -1954,6 +1950,19 @@ on_drag_motion (GtkWidget *widget, valid_location = TRUE; } + /* Check that the destination folder is writable */ + dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + folder = tree_path_to_folder (dest_model, dest_row); + if (folder) { + ModestTnyFolderRules rules = modest_tny_folder_get_rules(folder); + + if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) { + valid_location = FALSE; + goto out; + } + g_object_unref (folder); + } + /* Expand the selected row after 1/2 second */ if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) { gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos); @@ -1976,17 +1985,10 @@ on_drag_motion (GtkWidget *widget, if (dest_row) gtk_tree_path_free (dest_row); g_signal_stop_emission_by_name (widget, "drag-motion"); + return valid_location; } - -/* Folder view drag types */ -const GtkTargetEntry folder_view_drag_types[] = -{ - { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW }, - { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW } -}; - /* * This function sets the treeview as a source and a target for dnd * events. It also connects all the requirede signals. diff --git a/src/widgets/modest-header-view.c b/src/widgets/modest-header-view.c index 7dd0548..d5bb9da 100644 --- a/src/widgets/modest-header-view.c +++ b/src/widgets/modest-header-view.c @@ -1370,52 +1370,32 @@ cmp_subject_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *ite /* Drag and drop stuff */ static void -drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, +drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, GtkSelectionData *selection_data, - guint info, guint time, gpointer data) + guint info, + guint time, + gpointer data) { - GtkTreeModel *model = NULL; - GtkTreeIter iter; - GtkTreePath *source_row = NULL; -/* GtkTreeSelection *sel = NULL;*/ - - source_row = get_selected_row (GTK_TREE_VIEW (widget), &model); - - if ((source_row == NULL) || (!gtk_tree_model_get_iter(model, &iter, source_row))) return; + GtkTreeSelection *selection; + GtkTreeModel *model; + GList *selected_rows; - switch (info) { - case MODEST_HEADER_ROW: - gtk_tree_set_row_drag_data (selection_data, model, source_row); - break; - case MODEST_MSG: { - TnyHeader *hdr = NULL; - gtk_tree_model_get (model, &iter, - TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &hdr, - -1); - if (hdr) { - g_object_unref (G_OBJECT(hdr)); - } - break; - } - default: - g_message ("%s: default switch case.", __FUNCTION__); - } + /* Get selected rows */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + selected_rows = gtk_tree_selection_get_selected_rows (selection, &model); - /* commenting out the next, fixes NB#62963 */ -#if 0 - /* Set focus on next header */ - sel = gtk_tree_view_get_selection(GTK_TREE_VIEW (widget)); - gtk_tree_path_next (source_row); - gtk_tree_selection_select_path (sel, source_row); + /* Set the data */ + modest_dnd_selection_data_set_paths (selection_data, selected_rows); - gtk_tree_path_free (source_row); -#endif + /* Frees */ + g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (selected_rows); } /* Header view drag types */ const GtkTargetEntry header_view_drag_types[] = { - { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }, - { "text/uri-list", 0, MODEST_MSG }, + { GTK_TREE_PATH_AS_STRING_LIST, GTK_TARGET_SAME_APP, MODEST_HEADER_ROW } }; static void