--- /dev/null
+/* 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 <gtk/gtktreeview.h>
+#include <string.h>
+
+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; i<g_list_length(selected_rows) - 1; i++) {
+ g_string_append (list, gtk_tree_path_to_string (row->data));
+ 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;
+}
#include <modest-text-utils.h>
#include <modest-runtime.h>
#include "modest-folder-view.h"
-#include <modest-dnd.h>
#include <modest-platform.h>
#include <modest-widget-memory.h>
#include <modest-ui-actions.h>
+#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);
/*****************************************************************************/
/* 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
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
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,
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))
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
&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);
}
{
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);
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);
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.
/* 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