X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-header-view.c;h=753377a486ea62367da53c7f2113872786e836fc;hb=915c00d90d2a73db49dac99e958c6a8417fdb7da;hp=753b2c37a937b53e3b1229acc400257849755393;hpb=da6d9fc59bbcf86775a3418b7993eaf137bc8aca;p=modest diff --git a/src/widgets/modest-header-view.c b/src/widgets/modest-header-view.c index 753b2c3..753377a 100644 --- a/src/widgets/modest-header-view.c +++ b/src/widgets/modest-header-view.c @@ -30,32 +30,44 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include static void modest_header_view_class_init (ModestHeaderViewClass *klass); static void modest_header_view_init (ModestHeaderView *obj); static void modest_header_view_finalize (GObject *obj); -static gboolean on_header_clicked (GtkWidget *widget, GdkEventButton *event, gpointer user_data); -static void on_selection_changed (GtkTreeSelection *sel, gpointer user_data); +static gboolean on_header_clicked (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); -static gint cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, - gpointer user_data); +static gint cmp_rows (GtkTreeModel *tree_model, + GtkTreeIter *iter1, + GtkTreeIter *iter2, + gpointer user_data); + +static void on_selection_changed (GtkTreeSelection *sel, + gpointer user_data); + +static void setup_drag_and_drop (GtkTreeView *self); typedef struct _ModestHeaderViewPrivate ModestHeaderViewPrivate; struct _ModestHeaderViewPrivate { TnyFolder *folder; - TnyList *headers; - GMutex *lock; ModestHeaderViewStyle style; + + TnyFolderMonitor *monitor; + GMutex *monitor_lock; }; #define MODEST_HEADER_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ @@ -198,8 +210,6 @@ remove_all_columns (ModestHeaderView *obj) g_list_free (columns); } - - gboolean modest_header_view_set_columns (ModestHeaderView *self, const GList *columns) { @@ -219,11 +229,9 @@ modest_header_view_set_columns (ModestHeaderView *self, const GList *columns) remove_all_columns (self); - if (priv->headers) - sortable = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(priv->headers)); - else - sortable = NULL; - + sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + + /* Add new columns */ for (cursor = columns; cursor; cursor = g_list_next(cursor)) { ModestHeaderViewColumn col = (ModestHeaderViewColumn) GPOINTER_TO_INT(cursor->data); @@ -337,6 +345,7 @@ modest_header_view_set_columns (ModestHeaderView *self, const GList *columns) self); gtk_tree_view_append_column (GTK_TREE_VIEW(self), column); } + return TRUE; } @@ -347,8 +356,13 @@ modest_header_view_init (ModestHeaderView *obj) priv = MODEST_HEADER_VIEW_GET_PRIVATE(obj); - priv->lock = g_mutex_new (); + priv->folder = NULL; + + priv->monitor = NULL; + priv->monitor_lock = g_mutex_new (); + + setup_drag_and_drop (GTK_TREE_VIEW (obj)); } static void @@ -356,23 +370,22 @@ modest_header_view_finalize (GObject *obj) { ModestHeaderView *self; ModestHeaderViewPrivate *priv; - GtkTreeSelection *sel; self = MODEST_HEADER_VIEW(obj); priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); - if (priv->headers) - g_object_unref (G_OBJECT(priv->headers)); - - sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); - - if (priv->lock) { - g_mutex_free (priv->lock); - priv->lock = NULL; + g_mutex_lock (priv->monitor_lock); + if (priv->monitor) { + tny_folder_monitor_stop (priv->monitor); + g_object_unref (G_OBJECT (priv->monitor)); } + g_mutex_unlock (priv->monitor_lock); + g_mutex_free (priv->monitor_lock); - priv->headers = NULL; - priv->folder = NULL; + if (priv->folder) { + g_object_unref (G_OBJECT (priv->folder)); + priv->folder = NULL; + } G_OBJECT_CLASS(parent_class)->finalize (obj); } @@ -440,16 +453,14 @@ modest_header_view_get_selected_headers (ModestHeaderView *self) tmp = list; while (tmp) { /* get header from selection */ - gtk_tree_model_get_iter (tree_model, - &iter, - (GtkTreePath *) (tmp->data)); - + gtk_tree_model_get_iter (tree_model, &iter, (GtkTreePath *) (tmp->data)); gtk_tree_model_get (tree_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1); - /* Prepend to list */ tny_list_prepend (header_list, G_OBJECT (header)); + g_object_unref (G_OBJECT (header)); + tmp = g_list_next (tmp); } /* Clean up*/ @@ -459,6 +470,40 @@ modest_header_view_get_selected_headers (ModestHeaderView *self) return header_list; } + +/* scroll our list view so the selected item is visible */ +static void +scroll_to_selected (ModestHeaderView *self, GtkTreeIter *iter, gboolean up) +{ +#if MODEST_PLATFORM_ID==1 /* MODES_PLATFORM_ID: 1 ==> gtk, 2==> maemo */ + + GtkTreePath *selected_path; + GtkTreePath *start, *end; + + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW(self)); + selected_path = gtk_tree_model_get_path (model, iter); + + start = gtk_tree_path_new (); + end = gtk_tree_path_new (); + + gtk_tree_view_get_visible_range (GTK_TREE_VIEW(self), &start, &end); + + if (gtk_tree_path_compare (selected_path, start) < 0 || + gtk_tree_path_compare (end, selected_path) < 0) + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(self), + selected_path, NULL, TRUE, + up ? 0.0 : 1.0, + up ? 0.0 : 1.0); + gtk_tree_path_free (selected_path); + gtk_tree_path_free (start); + gtk_tree_path_free (end); + +#endif /* MODEST_PLATFORM_ID */ +} + + void modest_header_view_select_next (ModestHeaderView *self) { @@ -467,10 +512,11 @@ modest_header_view_select_next (ModestHeaderView *self) GtkTreeModel *model; sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self)); - if (sel) { - gtk_tree_selection_get_selected (sel, &model, &iter); - if (gtk_tree_model_iter_next (model, &iter)) + if (gtk_tree_selection_get_selected (sel, &model, &iter)) { + if (gtk_tree_model_iter_next (model, &iter)) { gtk_tree_selection_select_iter (sel, &iter); + scroll_to_selected (self, &iter, FALSE); + } } } @@ -483,16 +529,17 @@ modest_header_view_select_prev (ModestHeaderView *self) GtkTreePath *path; sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self)); - if (sel) { - gtk_tree_selection_get_selected (sel, &model, &iter); + if (gtk_tree_selection_get_selected (sel, &model, &iter)) { path = gtk_tree_model_get_path (model, &iter); /* Move path up */ if (gtk_tree_path_prev (path)) { gtk_tree_model_get_iter (model, &iter, path); - + /* Select the new one */ gtk_tree_selection_select_iter (sel, &iter); + scroll_to_selected (self, &iter, TRUE); + } gtk_tree_path_free (path); } @@ -555,64 +602,101 @@ modest_header_view_get_style (ModestHeaderView *self) return MODEST_HEADER_VIEW_GET_PRIVATE(self)->style; } +/* + * This function sets a sortable model in the header view. It's just + * used for developing purposes, because it only does a + * gtk_tree_view_set_model + */ +static void +modest_header_view_set_model (GtkTreeView *header_view, GtkTreeModel *model) +{ + GtkTreeModel *old_model_sort = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)); + + if (old_model_sort && GTK_IS_TREE_MODEL_SORT (old_model_sort)) { + GtkTreeModel *old_model; + + old_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (old_model_sort)); + gtk_tree_view_set_model (header_view, model); + modest_runtime_verify_object_death (old_model, ""); + modest_runtime_verify_object_death (old_model_sort, ""); + } else { + ModestHeaderViewPrivate *priv; + + priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view); + g_mutex_lock (priv->monitor_lock); + if (priv->monitor) { + tny_folder_monitor_stop (priv->monitor); + g_object_unref (G_OBJECT (priv->monitor)); + priv->monitor = NULL; + } + g_mutex_unlock (priv->monitor_lock); + gtk_tree_view_set_model (header_view, model); + } + + return; +} static void -on_refresh_folder (TnyFolder *folder, gboolean cancelled, GError **err, - gpointer user_data) +on_refresh_folder (TnyFolder *folder, + gboolean cancelled, + GError **error, + gpointer user_data) { GtkTreeModel *sortable; ModestHeaderView *self; ModestHeaderViewPrivate *priv; - GError *error = NULL; + GList *cols, *cursor; + TnyList *headers; if (cancelled) { - GtkTreeSelection *selection; +/* GtkTreeSelection *selection; */ + +/* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_data)); */ +/* gtk_tree_selection_unselect_all (selection); */ + + g_warning ("Operation cancelled %s\n", (*error) ? (*error)->message : "unknown"); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_data)); - gtk_tree_selection_unselect_all (selection); return; } self = MODEST_HEADER_VIEW(user_data); priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); - priv->folder = folder; - - if (folder) { /* it's a new one or a refresh */ - GList *cols, *cursor; - - if (priv->headers) - g_object_unref (priv->headers); - - priv->headers = TNY_LIST(tny_gtk_header_list_model_new ()); - tny_folder_get_headers (folder, priv->headers, FALSE, &error); /* FIXME */ - if (error) { - g_signal_emit (G_OBJECT(self), signals[ITEM_NOT_FOUND_SIGNAL], - 0, MODEST_ITEM_TYPE_MESSAGE); - g_print (error->message); - g_error_free (error); - return; - } + headers = TNY_LIST (tny_gtk_header_list_model_new ()); - tny_gtk_header_list_model_set_folder - (TNY_GTK_HEADER_LIST_MODEL(priv->headers),folder, TRUE); /*async*/ + tny_gtk_header_list_model_set_folder (TNY_GTK_HEADER_LIST_MODEL(headers), + folder, TRUE); - sortable = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(priv->headers)); + sortable = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(headers)); + g_object_unref (G_OBJECT (headers)); - /* install our special sorting functions */ - cursor = cols = gtk_tree_view_get_columns (GTK_TREE_VIEW(self)); - while (cursor) { - gint col_id = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cursor->data), - MODEST_HEADER_VIEW_COLUMN)); - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(sortable), - col_id, - (GtkTreeIterCompareFunc)cmp_rows, - cursor->data, NULL); - cursor = g_list_next(cursor); - } - g_list_free (cols); - gtk_tree_view_set_model (GTK_TREE_VIEW (self), sortable); + /* install our special sorting functions */ + cursor = cols = gtk_tree_view_get_columns (GTK_TREE_VIEW(self)); + while (cursor) { + gint col_id = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cursor->data), + MODEST_HEADER_VIEW_COLUMN)); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(sortable), + col_id, + (GtkTreeIterCompareFunc) cmp_rows, + cursor->data, NULL); + cursor = g_list_next(cursor); + } + g_list_free (cols); + + /* Add a folder observer */ + g_mutex_lock (priv->monitor_lock); + if (priv->monitor) { + tny_folder_monitor_stop (priv->monitor); + g_object_unref (G_OBJECT (priv->monitor)); } + priv->monitor = TNY_FOLDER_MONITOR (tny_folder_monitor_new (folder)); + tny_folder_monitor_add_list (priv->monitor, TNY_LIST (headers)); + tny_folder_monitor_start (priv->monitor); + g_mutex_unlock (priv->monitor_lock); + + /* Set new model */ + modest_header_view_set_model (GTK_TREE_VIEW (self), sortable); + g_object_unref (G_OBJECT (sortable)); } @@ -642,6 +726,9 @@ modest_header_view_get_folder (ModestHeaderView *self) ModestHeaderViewPrivate *priv; priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); + if (priv->folder) + g_object_ref (priv->folder); + return priv->folder; } @@ -652,17 +739,25 @@ modest_header_view_set_folder (ModestHeaderView *self, TnyFolder *folder) ModestHeaderViewPrivate *priv; priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); - priv->folder = folder; + if (priv->folder) { + g_object_unref (priv->folder); + priv->folder = NULL; + } if (folder) { + + priv->folder = g_object_ref (folder); + tny_folder_refresh_async (folder, on_refresh_folder, on_refresh_folder_status_update, self); - /* no message selected */ + /* no message selected */ g_signal_emit (G_OBJECT(self), signals[HEADER_SELECTED_SIGNAL], 0, NULL); + } else { + modest_header_view_set_model (GTK_TREE_VIEW (self), NULL); } } @@ -698,6 +793,9 @@ on_header_clicked (GtkWidget *widget, GdkEventButton *event, gpointer user_data) signals[HEADER_ACTIVATED_SIGNAL], 0, header); + /* Free */ + g_object_unref (G_OBJECT (header)); + return TRUE; } @@ -728,6 +826,8 @@ on_selection_changed (GtkTreeSelection *sel, gpointer user_data) g_signal_emit (G_OBJECT(self), signals[HEADER_SELECTED_SIGNAL], 0, header); + + g_object_unref (G_OBJECT (header)); } @@ -871,3 +971,49 @@ cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, return &iter1 - &iter2; /* oughhhh */ } } + +/* Drag and drop stuff */ +static void +drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *source_row; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + gtk_tree_selection_get_selected (selection, &model, &iter); + source_row = gtk_tree_model_get_path (model, &iter); + + gtk_tree_set_row_drag_data (selection_data, + model, + source_row); + + gtk_tree_path_free (source_row); +} + +/* Header view drag types */ +const GtkTargetEntry header_view_drag_types[] = +{ + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, HEADER_ROW } +}; + +static void +setup_drag_and_drop (GtkTreeView *self) +{ + gtk_drag_source_set (GTK_WIDGET (self), + GDK_BUTTON1_MASK, + header_view_drag_types, + G_N_ELEMENTS (header_view_drag_types), + GDK_ACTION_MOVE | GDK_ACTION_COPY); + + gtk_signal_connect(GTK_OBJECT (self), + "drag_data_get", + GTK_SIGNAL_FUNC(drag_data_get_cb), + NULL); +}