#include <tny-gtk-folder-store-tree-model.h>
#include <tny-gtk-header-list-model.h>
#include <tny-folder.h>
-#include <tny-folder-monitor.h>
#include <tny-account-store.h>
#include <tny-account.h>
#include <tny-folder.h>
#include <modest-runtime.h>
#include "modest-folder-view.h"
#include <modest-dnd.h>
+#include <modest-platform.h>
/* 'private'/'protected' functions */
static void modest_folder_view_class_init (ModestFolderViewClass *klass);
static gboolean update_model (ModestFolderView *self,
ModestTnyAccountStore *account_store);
-static gboolean update_model_empty (ModestFolderView *self);
-
static void on_selection_changed (GtkTreeSelection *sel, gpointer data);
static void on_account_update (TnyAccountStore *account_store,
gulong account_update_signal;
gulong changed_signal;
gulong accounts_reloaded_signal;
- GMutex *lock;
GtkTreeSelection *cur_selection;
TnyFolderStoreQuery *query;
guint timer_expander;
-
- TnyFolderMonitor *monitor;
};
#define MODEST_FOLDER_VIEW_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE((o), \
}
}
} else if (folder && type == TNY_FOLDER_TYPE_ROOT) {
- if (strcmp (fname, MODEST_LOCAL_FOLDERS_ACCOUNT_NAME) == 0) {/* FIXME: hack */
- g_free (fname);
- fname = g_strdup (MODEST_LOCAL_FOLDERS_DISPLAY_NAME);
- }
+ /* FIXME: todo */
}
if (unread > 0) {
}
-static GdkPixbuf*
-get_cached_icon (const gchar *name)
-{
- GError *err = NULL;
- gpointer pixbuf;
- gpointer orig_key;
- static GHashTable *icon_cache = NULL;
-
- g_return_val_if_fail (name, NULL);
-
- if (G_UNLIKELY(!icon_cache))
- icon_cache = modest_cache_mgr_get_cache (modest_runtime_get_cache_mgr(),
- MODEST_CACHE_MGR_CACHE_TYPE_PIXBUF);
-
- if (!icon_cache || !g_hash_table_lookup_extended (icon_cache, name, &orig_key, &pixbuf)) {
- pixbuf = (gpointer)gdk_pixbuf_new_from_file (name, &err);
- if (!pixbuf) {
- g_printerr ("modest: error in icon factory while loading '%s': %s\n",
- name, err->message);
- g_error_free (err);
- }
- /* if we cannot find it, we still insert (if we have a cache), so we get the error
- * only once */
- if (icon_cache)
- g_hash_table_insert (icon_cache, g_strdup(name),(gpointer)pixbuf);
- }
- return GDK_PIXBUF(pixbuf);
-}
-
static void
icon_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
switch (type) {
case TNY_FOLDER_TYPE_ROOT:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_ACCOUNT);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
break;
case TNY_FOLDER_TYPE_INBOX:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_INBOX);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
break;
case TNY_FOLDER_TYPE_OUTBOX:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_OUTBOX);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
break;
case TNY_FOLDER_TYPE_JUNK:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_JUNK);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
break;
case TNY_FOLDER_TYPE_SENT:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_SENT);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
break;
case TNY_FOLDER_TYPE_TRASH:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_TRASH);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
break;
case TNY_FOLDER_TYPE_DRAFTS:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_DRAFTS);
- break;
- case TNY_FOLDER_TYPE_NOTES:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_NOTES);
- break;
- case TNY_FOLDER_TYPE_CALENDAR:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_CALENDAR);
- break;
- case TNY_FOLDER_TYPE_CONTACTS:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_CONTACTS);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
break;
case TNY_FOLDER_TYPE_NORMAL:
default:
- pixbuf = get_cached_icon (MODEST_FOLDER_ICON_NORMAL);
+ pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
break;
}
g_object_set (rendobj, "pixbuf", pixbuf, NULL);
priv->cur_folder = NULL;
priv->cur_row = NULL;
priv->query = NULL;
- priv->monitor = NULL;
-
- priv->lock = g_mutex_new ();
column = gtk_tree_view_column_new ();
- gtk_tree_view_append_column (GTK_TREE_VIEW(obj),column);
renderer = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(obj), FALSE);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW(obj), FALSE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW(obj),column);
+
setup_drag_and_drop (GTK_TREE_VIEW(obj));
}
priv->account_store = NULL;
}
- if (priv->lock) {
- g_mutex_free (priv->lock);
- priv->lock = NULL;
- }
-
if (priv->query) {
g_object_unref (G_OBJECT (priv->query));
priv->query = NULL;
return GTK_WIDGET(self);
}
-
-static gboolean
-update_model_empty (ModestFolderView *self)
-{
- ModestFolderViewPrivate *priv;
-
- g_return_val_if_fail (self, FALSE);
- priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
-
- g_mutex_lock (priv->lock);
- {
- if (priv->monitor) {
- tny_folder_monitor_stop (priv->monitor);
- g_object_unref(G_OBJECT(priv->monitor));
- priv->monitor = NULL;
- }
- }
- g_mutex_unlock (priv->lock);
-
- g_signal_emit (G_OBJECT(self), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
- NULL, TRUE);
- return TRUE;
-}
-
-
/* this feels dirty; any other way to expand all the root items? */
static void
expand_root_items (ModestFolderView *self)
priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
- /* Notify that there is no folder selected */
- update_model_empty (self);
+ /* Notify that there is no folder selected*/
+ g_signal_emit (G_OBJECT(self),
+ signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
+ NULL, TRUE);
/* FIXME: the local accounts are not shown when the query
selects only the subscribed folders. */
/* folder was _un_selected if true */
if (!gtk_tree_selection_get_selected (sel, &model_sort, &iter_sort)) {
- priv->cur_folder = NULL; /* FIXME: need this? */
- gtk_tree_row_reference_free (priv->cur_row);
+ if (priv->cur_folder)
+ g_object_unref (priv->cur_folder);
+ if (priv->cur_row)
+ gtk_tree_row_reference_free (priv->cur_row);
+ priv->cur_folder = NULL;
priv->cur_row = NULL;
return;
}
TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
-1);
- if (type == TNY_FOLDER_TYPE_ROOT) {
+ /* If the folder is the same or is a root folder do not notify */
+ if ((type == TNY_FOLDER_TYPE_ROOT) || (priv->cur_folder == folder)) {
g_object_unref (folder);
return;
}
/* Current folder was unselected */
- g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
- priv->cur_folder, FALSE);
+ if (priv->cur_folder) {
+ g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
+ priv->cur_folder, FALSE);
+ g_object_unref (priv->cur_folder);
+ }
- if (priv->cur_row) {
-/* tny_folder_sync (priv->cur_folder, TRUE, NULL); /\* FIXME *\/ */
+ if (priv->cur_row)
gtk_tree_row_reference_free (priv->cur_row);
- }
/* New current references */
path = gtk_tree_model_get_path (model_sort, &iter_sort);
/* Frees */
gtk_tree_path_free (path);
- g_object_unref (G_OBJECT (folder));
/* New folder has been selected */
g_signal_emit (G_OBJECT(tree_view),
return priv->cur_folder;
}
-/* static gboolean */
-/* get_model_iter (ModestFolderView *self, */
-/* GtkTreeModel **model, */
-/* GtkTreeIter *iter) */
-/* { */
-/* GtkTreeModel *model_sort; */
-/* GtkTreeIter iter_sort; */
-/* GtkTreePath *path; */
-/* ModestFolderViewPrivate *priv; */
-
-/* priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self); */
-
-/* if (!priv->cur_folder) */
-/* return FALSE; */
-
-/* if (!gtk_tree_row_reference_valid (priv->cur_row)) */
-/* return FALSE; */
-
-/* model_sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); */
-/* *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model_sort)); */
-
-/* /\* Get path to retrieve iter *\/ */
-/* path = gtk_tree_row_reference_get_path (priv->cur_row); */
-/* if (!gtk_tree_model_get_iter (model_sort, &iter_sort, path)) */
-/* return FALSE; */
-
-/* gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model_sort), */
-/* iter, */
-/* &iter_sort); */
-/* return TRUE; */
-/* } */
-
static gint
cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
gpointer user_data)
gtk_tree_path_free (source_row);
}
-typedef struct _DndHelper
-{
+typedef struct _DndHelper {
gboolean delete_source;
- GtkWidget *source_widget;
- GtkWidget *dest_widget;
GtkTreePath *source_row;
GdkDragContext *context;
guint time;
/*
- * This function saves the source row in the source widget, will be
- * used by the drag-data-delete handler to remove the source row
- */
-static void
-save_and_clean (DndHelper *helper,
- gboolean success)
-{
- /* Save row data */
- if (success && helper->delete_source)
- g_object_set_data (G_OBJECT (helper->source_widget),
- ROW_REF_DATA_NAME,
- gtk_tree_path_copy (helper->source_row));
-
- /* Clean dest row */
- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (helper->dest_widget),
- NULL,
- GTK_TREE_VIEW_DROP_BEFORE);
-
-}
-
-/*
* This function is the callback of the
- * modest_mail_operation_xfer_msg() call. We check here if the message
- * was correctly asynchronously transfered
+ * modest_mail_operation_xfer_msg() 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, gpointer user_data)
{
- ModestMailOperationQueue *queue;
- gboolean success = FALSE;
+ gboolean success;
DndHelper *helper;
helper = (DndHelper *) user_data;
+ if (!modest_mail_operation_is_finished (mail_op))
+ return;
+
if (modest_mail_operation_get_status (mail_op) ==
MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
success = TRUE;
} else {
- const GError *error;
- error = modest_mail_operation_get_error (mail_op);
- g_warning ("Error transferring messages: %s\n", error->message);
+ success = FALSE;
}
- /* Remove the mail operation */
- queue = modest_runtime_get_mail_operation_queue ();
- modest_mail_operation_queue_remove (queue, mail_op);
- g_object_unref (G_OBJECT (mail_op));
-
- /* Save and clean */
- save_and_clean (helper, success);
-
- /* Notify the drag source */
- gtk_drag_finish (helper->context, success, (success && helper->delete_source), helper->time);
+ /* 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);
}
{
TnyHeader *header;
TnyFolder *folder;
- ModestMailOperationQueue *queue;
ModestMailOperation *mail_op;
- gboolean started;
GtkTreeIter source_iter, dest_iter;
/* Get header */
&folder, -1);
/* Transfer message */
- queue = modest_runtime_get_mail_operation_queue ();
mail_op = modest_mail_operation_new ();
- started = modest_mail_operation_xfer_msg (mail_op, header,
- folder, helper->delete_source);
- if (started) {
- g_signal_connect (G_OBJECT (mail_op), "progress_changed",
- G_CALLBACK (on_progress_changed), helper);
- modest_mail_operation_queue_add (queue, mail_op);
- } else {
- const GError *error;
- error = modest_mail_operation_get_error (mail_op);
- if (error)
- g_warning ("Error trying to transfer messages: %s\n",
- error->message);
+ 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);
- g_slice_free (DndHelper, helper);
- }
+ modest_mail_operation_xfer_msg (mail_op, header, folder, helper->delete_source);
/* Frees */
g_object_unref (G_OBJECT (mail_op));
DndHelper *helper)
{
ModestMailOperation *mail_op;
- const GError *error;
- GtkTreeRowReference *source_row_reference;
GtkTreeIter parent_iter, iter;
- TnyFolder *folder, *new_folder;
TnyFolderStore *parent_folder;
- gboolean success = FALSE;
+ TnyFolder *folder;
/* Check if the drag is possible */
- if (!gtk_tree_path_compare (helper->source_row, dest_row))
- goto out;
-
- if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (dest_model),
+ 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))
- goto out;
+ selection_data)) {
+
+ 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);
/* Do the mail operation */
mail_op = modest_mail_operation_new ();
- new_folder = modest_mail_operation_xfer_folder (mail_op, folder, parent_folder,
- helper->delete_source);
+ 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));
-
- error = modest_mail_operation_get_error (mail_op);
- if (error) {
- g_warning ("Error transferring folder: %s\n", error->message);
- g_object_unref (G_OBJECT (mail_op));
- goto out;
- }
g_object_unref (G_OBJECT (mail_op));
-
- /* Get a row reference to the source path because the path
- could change after the insertion. The gtk_drag_finish() is
- not able to delete the source because that, so we have to
- do it manually */
- source_row_reference = gtk_tree_row_reference_new (source_model, helper->source_row);
- gtk_tree_path_free (helper->source_row);
-
- /* Insert the dragged row as a child of the dest row */
- gtk_tree_path_down (dest_row);
- if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (dest_model),
- dest_row,
- selection_data)) {
-
- GtkTreeIter iter;
-
- /* Set the newly created folder as the instance in the row */
- gtk_tree_model_get_iter (dest_model, &iter, dest_row);
- gtk_tree_store_set (GTK_TREE_STORE (dest_model), &iter,
- TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
- new_folder, -1);
- g_object_unref (G_OBJECT (new_folder));
-
- helper->source_row = gtk_tree_row_reference_get_path (source_row_reference);
-
- success = TRUE;
- }
- gtk_tree_row_reference_free (source_row_reference);
-
- /* Save and clean */
- save_and_clean (helper, success);
-
- out:
- gtk_drag_finish (helper->context, success, (success && helper->delete_source), helper->time);
}
/*
/* Check if the get_data failed */
if (selection_data == NULL || selection_data->length < 0)
- gtk_drag_finish (context, success, (success && delete_source), time);
+ gtk_drag_finish (context, success, FALSE, time);
/* Get the models */
source_widget = gtk_drag_get_source_widget (context);
/* Only allow drops IN other rows */
if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER)
- gtk_drag_finish (context, success, (success && delete_source), time);
+ gtk_drag_finish (context, success, FALSE, time);
/* Create the helper */
helper = g_slice_new0 (DndHelper);
helper->delete_source = delete_source;
- helper->source_widget = source_widget;
- helper->dest_widget = widget;
- helper->source_row = source_row;
+ helper->source_row = gtk_tree_path_copy (source_row);
helper->context = context;
helper->time = time;
selection_data,
helper);
}
+
+ /* Frees */
+ gtk_tree_path_free (source_row);
gtk_tree_path_free (child_dest_row);
}
}
/*
- * This function deletes the data that has been dragged from its
- * source widget. Since is a function received by the source of the
- * drag, this function only deletes rows of the folder view
- * widget. The header view widget will need to define its own one.
- */
-static void
-drag_data_delete_cb (GtkWidget *widget,
- GdkDragContext *context,
- gpointer user_data)
-{
- GtkTreePath *source_row;
- GtkTreeModel *model_sort, *model;
-
- model_sort = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
- model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model_sort));
- source_row = g_object_steal_data (G_OBJECT (widget), ROW_REF_DATA_NAME);
-
- /* Delete the source row */
- gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
- source_row);
-
- gtk_tree_path_free (source_row);
-}
-
-/*
* This function expands a node of a tree view if it's not expanded
* yet. Not sure why it needs the threads stuff, but gtk+`example code
* does that, so that's why they're here.
GtkTreePath *dest_row;
ModestFolderViewPrivate *priv;
GdkDragAction suggested_action;
+ gboolean valid_location = FALSE;
priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
&dest_row,
&pos);
- if (!dest_row)
- return FALSE;
+ /* Do not allow drops between folders */
+ if (!dest_row ||
+ pos == GTK_TREE_VIEW_DROP_BEFORE ||
+ pos == GTK_TREE_VIEW_DROP_AFTER) {
+ gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
+ gdk_drag_status(context, 0, time);
+ valid_location = FALSE;
+ goto out;
+ } else {
+ valid_location = TRUE;
+ }
/* Expand the selected row after 1/2 second */
if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
else
gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
- return TRUE;
+ out:
+ 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, FOLDER_ROW },
- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, HEADER_ROW }
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
};
/*
G_N_ELEMENTS (folder_view_drag_types),
GDK_ACTION_MOVE | GDK_ACTION_COPY);
- gtk_signal_connect(GTK_OBJECT (self),
- "drag_data_received",
- GTK_SIGNAL_FUNC(on_drag_data_received),
- NULL);
+ g_signal_connect (G_OBJECT (self),
+ "drag_data_received",
+ G_CALLBACK (on_drag_data_received),
+ NULL);
/* Set up the treeview as a dnd source */
G_N_ELEMENTS (folder_view_drag_types),
GDK_ACTION_MOVE | GDK_ACTION_COPY);
- gtk_signal_connect(GTK_OBJECT (self),
- "drag_data_delete",
- GTK_SIGNAL_FUNC(drag_data_delete_cb),
- NULL);
-
- gtk_signal_connect(GTK_OBJECT (self),
- "drag_motion",
- GTK_SIGNAL_FUNC(on_drag_motion),
- NULL);
-
-
- gtk_signal_connect(GTK_OBJECT (self),
- "drag_data_get",
- GTK_SIGNAL_FUNC(on_drag_data_get),
- NULL);
-
- gtk_signal_connect(GTK_OBJECT (self),
- "drag_drop",
- GTK_SIGNAL_FUNC(drag_drop_cb),
- NULL);
+ g_signal_connect (G_OBJECT (self),
+ "drag_motion",
+ G_CALLBACK (on_drag_motion),
+ NULL);
+
+ g_signal_connect (G_OBJECT (self),
+ "drag_data_get",
+ G_CALLBACK (on_drag_data_get),
+ NULL);
+
+ g_signal_connect (G_OBJECT (self),
+ "drag_drop",
+ G_CALLBACK (drag_drop_cb),
+ NULL);
}