Patch: TnyGtkHeaderListModel showing only latest headers



	Hi,

	This patch adds to the TnyGtkHeaderListModel a method that limits the
number of messages loaded as treeview elements.

	It assumes the messages are stored in summary more or less by date
(latest ones in summary would be more recent elements). But in case it
finds other messages more recent than the ones in this "latest" set,
then it will also show them. (in other words, it shows N latest and any
message newer than those N latest).

	This should at least limit performance and user experience problems
showing and sorting in a treeview a folder with huge number of messages.

	Changelog entries:

    New API for making TnyGtkHeaderListModel only show the latest messages,
    and allow from UI to fetch incrementally more messages. This
    implementation only avoids exposing the old headers as members of the
    GtkListStore.
    
    * libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h,
      libtinymailui-gtk/tny-gtk-header-list-model.c,
      libtinymailui-gtk/tny-gtk-header-list-model.h: new methods
      (get|set)_show_latest for limitting the number of items shown in list
      store.


    Ignore "show latest" in header list model, on adding elements newer than
    latest element visible.
    
        * libtinymailui-gtk/tny-gtk-header-list-model.c,
        libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h:
        only filter using "show latest" if the message is older than other
        messages already retrieved.


-- 
José Dapena Paz <jdapena igalia com>
Igalia
diff --git a/ChangeLog b/ChangeLog
index 331c8fa..4fa132d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2009-11-03  Jose Dapena Paz  <jdapena igalia com>
+
+	* libtinymailui-gtk/tny-gtk-header-list-model.c,
+	libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h:
+	only filter using "show latest" if the message is older than other
+	messages already retrieved.
+
+2009-10-30  Jose Dapena Paz  <jdapena igalia com>
+
+	New API for making TnyGtkHeaderListModel only show the latest messages,
+	and allow from UI to fetch incrementally more messages. This
+	implementation only avoids exposing the old headers as members of the
+	GtkListStore.
+
+	* libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h,
+	libtinymailui-gtk/tny-gtk-header-list-model.c,
+	libtinymailui-gtk/tny-gtk-header-list-model.h: new methods
+	(get|set)_show_latest for limitting the number of items shown in list
+	store.
+
 2009-10-26  Sergio Villar Senin  <svillar igalia com>
 
 	Fixed a lot of memory leaks in CamelException's
diff --git a/libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h b/libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h
index 8293f23..27d2bda 100644
--- a/libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h
+++ b/libtinymailui-gtk/tny-gtk-header-list-iterator-priv.h
@@ -81,6 +81,9 @@ struct _TnyGtkHeaderListModelPriv
 	GArray *del_timeouts;
 	TnyIterator *iterator;
 	gboolean no_duplicates;
+	gint show_latest;
+	GPtrArray *not_latest_items;
+	time_t oldest_received;
 };
 
 G_END_DECLS
diff --git a/libtinymailui-gtk/tny-gtk-header-list-model.c b/libtinymailui-gtk/tny-gtk-header-list-model.c
index 8d4a4cb..f1dcbf7 100644
--- a/libtinymailui-gtk/tny-gtk-header-list-model.c
+++ b/libtinymailui-gtk/tny-gtk-header-list-model.c
@@ -62,6 +62,7 @@ static GObjectClass *parent_class;
 #include "tny-common-priv.h"
 #undef TINYMAIL_ENABLE_PRIVATE_API
 
+static void update_oldest_received (TnyGtkHeaderListModel *self, TnyHeader *header);
 
 static gint 
 add_del_timeout (TnyGtkHeaderListModel *me, guint num)
@@ -737,6 +738,7 @@ static void
 tny_gtk_header_list_model_prepend (TnyList *self, GObject* item)
 {
 	TnyGtkHeaderListModelPriv *priv = TNY_GTK_HEADER_LIST_MODEL_GET_PRIVATE (self);
+	gboolean newer;
 
 	g_static_rec_mutex_lock (priv->iterator_lock);
 
@@ -756,20 +758,35 @@ tny_gtk_header_list_model_prepend (TnyList *self, GObject* item)
 
 	g_mutex_lock (priv->ra_lock);
 
-	g_ptr_array_add (priv->items, item);
+	if (priv->oldest_received > 0) {
+		newer = tny_header_get_date_received (TNY_HEADER (item)) > 
+			priv->oldest_received;
+	} else {
+		newer = TRUE;
+	}
+
+	if (!newer && (priv->show_latest && priv->items->len >= priv->show_latest)) {
+		g_ptr_array_add (priv->not_latest_items, item);
+	} else {
 
-	/* This prepend will happen very often, the notificating of the view is, 
-	 * however, quite slow and gdk wants us to do this from the mainloop */
+		g_ptr_array_add (priv->items, item);
+		update_oldest_received (TNY_GTK_HEADER_LIST_MODEL (self), TNY_HEADER (item));
+		if (priv->items->len > priv->show_latest)
+			priv->show_latest = priv->items->len;
 
-	if (priv->updating_views == -1)
-	{
-		priv->updating_views = 0;
-		g_object_ref (self);
+		/* This prepend will happen very often, the notificating of the view is, 
+		 * however, quite slow and gdk wants us to do this from the mainloop */
 
-		if (priv->add_timeout == 0) {
-			priv->add_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 
-								priv->timeout_span, notify_views_add, self, 
-								notify_views_add_destroy);
+		if (priv->updating_views == -1)
+		{
+			priv->updating_views = 0;
+			g_object_ref (self);
+
+			if (priv->add_timeout == 0) {
+				priv->add_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 
+									priv->timeout_span, notify_views_add, self, 
+									notify_views_add_destroy);
+			}
 		}
 	}
 
@@ -1014,7 +1031,7 @@ tny_gtk_header_list_model_get_length (TnyList *self)
 	guint retval = 0;
 
 	g_static_rec_mutex_lock (priv->iterator_lock);
-	retval = priv->items->len;
+	retval = priv->items->len + priv->not_latest_items->len;
 	g_static_rec_mutex_unlock (priv->iterator_lock);
 
 	return retval;
@@ -1054,6 +1071,10 @@ tny_gtk_header_list_model_copy_the_list (TnyList *self)
 	items_copy = g_ptr_array_sized_new (priv->items->len);
 	g_ptr_array_foreach (priv->items, copy_it, items_copy);
 	cpriv->items = items_copy;
+	items_copy = g_ptr_array_sized_new (priv->not_latest_items->len);
+	g_ptr_array_foreach (priv->not_latest_items, copy_it, items_copy);
+	cpriv->not_latest_items = items_copy;
+	cpriv->show_latest = priv->show_latest;
 	g_static_rec_mutex_unlock (priv->iterator_lock);
 
 	return TNY_LIST (copy);
@@ -1135,15 +1156,21 @@ tny_gtk_header_list_model_finalize (GObject *object)
 	remove_del_timeouts (self);
 
 	g_ptr_array_foreach (priv->items, (GFunc) copy_them, copy);
+	free_items (copy);
 
+	copy = g_ptr_array_new ();
+	g_ptr_array_foreach (priv->not_latest_items, (GFunc) copy_them, copy);
 	free_items (copy);
+
 	// g_timeout_add (5*100, free_items, copy);
 
 
 	if (priv->folder)
 		g_object_unref (priv->folder);
 	g_ptr_array_free (priv->items, TRUE);
+	g_ptr_array_free (priv->not_latest_items, TRUE);
 	priv->items = NULL;
+	priv->not_latest_items = NULL;
 
 	g_static_rec_mutex_unlock (priv->iterator_lock);
 
@@ -1188,6 +1215,7 @@ tny_gtk_header_list_model_init (TnyGtkHeaderListModel *self)
 	self->priv = priv;
 
 	priv->no_duplicates = FALSE;
+	priv->show_latest = 0;
 	priv->folder = NULL;
 	priv->iterator_lock = g_new0 (GStaticRecMutex, 1);
 	g_static_rec_mutex_init (priv->iterator_lock);
@@ -1197,6 +1225,7 @@ tny_gtk_header_list_model_init (TnyGtkHeaderListModel *self)
 	priv->del_timeouts = NULL;
 	priv->add_timeout = 0;
 	priv->items = g_ptr_array_sized_new (1000);
+	priv->not_latest_items = g_ptr_array_sized_new (1000);
 	priv->updating_views = -1;
 	priv->ra_lock = g_mutex_new ();
 	priv->to_lock = g_mutex_new ();
@@ -1272,6 +1301,7 @@ tny_gtk_header_list_model_set_folder (TnyGtkHeaderListModel *self, TnyFolder *fo
 	GtkTreeIter iter;
 	GtkTreePath *path;
 	GPtrArray *copy_items;
+	GPtrArray *copy_not_latest_items;
 
 	g_static_rec_mutex_lock (priv->iterator_lock);
 
@@ -1288,8 +1318,10 @@ tny_gtk_header_list_model_set_folder (TnyGtkHeaderListModel *self, TnyFolder *fo
 	 * assertion is placed there, in stead of a normal return, though) */
  
 	copy_items = priv->items;
+	copy_not_latest_items = priv->not_latest_items;
 	priv->registered = 0;
-	priv->items = g_ptr_array_sized_new (tny_folder_get_all_count (folder));
+	priv->items = g_ptr_array_sized_new (priv->show_latest?MIN (tny_folder_get_all_count (folder),priv->show_latest):tny_folder_get_all_count (folder));
+	priv->not_latest_items = g_ptr_array_sized_new (tny_folder_get_all_count (folder));
 	if (priv->folder)
 		g_object_unref (priv->folder);
 	priv->folder = TNY_FOLDER (g_object_ref (folder));
@@ -1307,6 +1339,8 @@ tny_gtk_header_list_model_set_folder (TnyGtkHeaderListModel *self, TnyFolder *fo
 
 	g_ptr_array_foreach (copy_items, (GFunc) g_object_unref, NULL);
 	g_ptr_array_free (copy_items, TRUE);
+	g_ptr_array_foreach (copy_not_latest_items, (GFunc) g_object_unref, NULL);
+	g_ptr_array_free (copy_not_latest_items, TRUE);
 
 	/* Reference the new folder instance */
 
@@ -1436,3 +1470,70 @@ tny_gtk_header_list_model_column_get_type (void)
 	g_once (&once, tny_gtk_header_list_model_column_register_type, NULL);
 	return GPOINTER_TO_UINT (once.retval);
 }
+
+void 
+tny_gtk_header_list_model_set_show_latest (TnyGtkHeaderListModel *self, gint show_latest_n)
+{
+	TnyGtkHeaderListModelPriv *priv = TNY_GTK_HEADER_LIST_MODEL_GET_PRIVATE (self);
+	gint recover_latest = 0;
+
+	if (priv->not_latest_items->len > 0 && show_latest_n == 0) {
+		/* recover all elements */
+		recover_latest = priv->not_latest_items->len;
+	} else if (show_latest_n > priv->show_latest) {
+		recover_latest = MIN (show_latest_n - priv->show_latest, priv->not_latest_items->len);
+	}
+
+	if (recover_latest > 0) {
+		gint i;
+		for (i = 0; i < recover_latest; i++) {
+			GObject *item = priv->not_latest_items->pdata[i];
+
+			g_ptr_array_add (priv->items, item);
+			update_oldest_received (TNY_GTK_HEADER_LIST_MODEL (self), TNY_HEADER (item));
+			if (priv->items->len > priv->show_latest)
+				priv->show_latest = priv->items->len;
+
+			if (priv->updating_views == -1)
+			{
+				priv->updating_views = 0;
+				g_object_ref (self);
+
+				if (priv->add_timeout == 0) {
+					priv->add_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 
+										priv->timeout_span, notify_views_add, self, 
+										notify_views_add_destroy);
+				}
+			}
+		}
+		g_ptr_array_remove_range (priv->not_latest_items, 0, recover_latest);
+	}
+
+	priv->show_latest = show_latest_n;
+
+}
+
+gint 
+tny_gtk_header_list_model_get_show_latest (TnyGtkHeaderListModel *self)
+{
+	TnyGtkHeaderListModelPriv *priv = TNY_GTK_HEADER_LIST_MODEL_GET_PRIVATE (self);
+
+	return priv->show_latest;
+}
+
+static void
+update_oldest_received (TnyGtkHeaderListModel *self, TnyHeader *header)
+{
+	TnyGtkHeaderListModelPriv *priv = TNY_GTK_HEADER_LIST_MODEL_GET_PRIVATE (self);
+	time_t date_received;
+
+	if (priv->oldest_received == 0) {
+		priv->oldest_received = tny_header_get_date_received (header);
+		return;
+	}
+
+	date_received = tny_header_get_date_received (header);
+	if (date_received < priv->oldest_received) {
+		priv->oldest_received = date_received;
+	}
+}
diff --git a/libtinymailui-gtk/tny-gtk-header-list-model.h b/libtinymailui-gtk/tny-gtk-header-list-model.h
index da4024d..3726fde 100644
--- a/libtinymailui-gtk/tny-gtk-header-list-model.h
+++ b/libtinymailui-gtk/tny-gtk-header-list-model.h
@@ -77,6 +77,8 @@ gint tny_gtk_header_list_model_received_date_sort_func (GtkTreeModel *model, Gtk
 gint tny_gtk_header_list_model_sent_date_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data);
 void tny_gtk_header_list_model_set_no_duplicates (TnyGtkHeaderListModel *self, gboolean setting);
 gboolean tny_gtk_header_list_model_get_no_duplicates (TnyGtkHeaderListModel *self);
+void tny_gtk_header_list_model_set_show_latest (TnyGtkHeaderListModel *self, gint show_latest_n);
+gint tny_gtk_header_list_model_get_show_latest (TnyGtkHeaderListModel *self);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]