+typedef struct _DndHelper {
+ gboolean delete_source;
+ GtkTreePath *source_row;
+ GdkDragContext *context;
+ guint time;
+} DndHelper;
+
+
+/*
+ * This function is the callback of the
+ * modest_mail_operation_xfer_msgs () and
+ * modest_mail_operation_xfer_folder() calls. We check here if the
+ * message/folder was correctly asynchronously transferred. The reason
+ * to use the same callback is that the code is the same, it only has
+ * to check that the operation went fine and then finalize the drag
+ * and drop action
+ */
+static void
+on_progress_changed (ModestMailOperation *mail_op,
+ ModestMailOperationState *state,
+ gpointer user_data)
+{
+ gboolean success;
+ DndHelper *helper;
+
+ helper = (DndHelper *) user_data;
+
+ if (!state->finished)
+ return;
+
+ if (state->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+
+ /* Notify the drag source. Never call delete, the monitor will
+ do the job if needed */
+ gtk_drag_finish (helper->context, success, FALSE, helper->time);
+
+ /* Free the helper */
+ gtk_tree_path_free (helper->source_row);
+ g_slice_free (DndHelper, helper);
+}
+
+/*
+ * 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
+ * view.
+ */
+static void
+drag_and_drop_from_header_view (GtkTreeModel *source_model,
+ GtkTreeModel *dest_model,
+ GtkTreePath *dest_row,
+ DndHelper *helper)
+{
+ TnyList *headers = NULL;
+ TnyHeader *header = NULL;
+ TnyFolder *folder = NULL;
+ ModestMailOperation *mail_op = NULL;
+ GtkTreeIter source_iter, dest_iter;
+
+ 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;
+ }
+
+ /* Get 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);
+
+ if (!TNY_IS_FOLDER(folder)) {
+ g_warning ("BUG: %s could not get a valid folder", __FUNCTION__);
+ goto cleanup;
+ }
+
+ /* Transfer message */
+ mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, NULL);
+ modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
+ mail_op);
+ g_signal_connect (G_OBJECT (mail_op), "progress-changed",
+ G_CALLBACK (on_progress_changed), helper);
+
+ headers = tny_simple_list_new ();
+ tny_list_append (headers, G_OBJECT (header));
+ modest_mail_operation_xfer_msgs (mail_op,
+ headers,
+ folder,
+ helper->delete_source,
+ NULL, NULL);
+
+ /* Frees */
+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))
+ g_object_unref (headers);
+}
+
+/*
+ * This function is used by drag_data_received_cb to manage drag and
+ * drop of a folder, i.e, and drag from the folder view to the same
+ * folder view.
+ */
+static void
+drag_and_drop_from_folder_view (GtkTreeModel *source_model,
+ GtkTreeModel *dest_model,
+ GtkTreePath *dest_row,
+ GtkSelectionData *selection_data,
+ DndHelper *helper)
+{
+ ModestMailOperation *mail_op;
+ GtkTreeIter parent_iter, iter;
+ TnyFolderStore *parent_folder;
+ TnyFolder *folder;
+
+ /* Check if the drag is possible */
+/* if (!gtk_tree_path_compare (helper->source_row, dest_row) || */
+/* !gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (dest_model), */
+/* dest_row, */
+/* selection_data)) { */
+ if (!gtk_tree_path_compare (helper->source_row, dest_row)) {
+
+ gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
+ gtk_tree_path_free (helper->source_row);
+ g_slice_free (DndHelper, helper);
+ return;
+ }
+
+ /* Get data */
+ gtk_tree_model_get_iter (source_model, &parent_iter, dest_row);
+ gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
+ gtk_tree_model_get (source_model, &parent_iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
+ &parent_folder, -1);
+ gtk_tree_model_get (source_model, &iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
+ &folder, -1);
+
+ /* Do the mail operation */
+ 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);
+ g_signal_connect (G_OBJECT (mail_op), "progress-changed",
+ G_CALLBACK (on_progress_changed), helper);
+
+ modest_mail_operation_xfer_folder (mail_op,
+ folder,
+ parent_folder,
+ helper->delete_source);
+
+ /* Frees */
+ g_object_unref (G_OBJECT (parent_folder));
+ g_object_unref (G_OBJECT (folder));
+ g_object_unref (G_OBJECT (mail_op));
+}
+
+/*
+ * This function receives the data set by the "drag-data-get" signal
+ * handler. This information comes within the #GtkSelectionData. This
+ * function will manage both the drags of folders of the treeview and
+ * drags of headers of the header view widget.
+ */