[gnome-photos] view-model: Try to constrain the addition of new items



commit 3823de8dfa76653ca13070136df261c3db278625
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Jan 20 10:49:47 2014 +0100

    view-model: Try to constrain the addition of new items
    
    We want to show content in steps of N items, sorted by their mtime in
    descending order. The value of N and the current offset is represented
    by PhotosOffsetController. Normally, this works because these limits
    are embedded in our SPARQL queries:
      "ORDER BY DESC (?mtime) LIMIT 50 OFFSET 100"
    
    However, when reacting to "graph-updated" signals we were adding items
    to PhotosViewModel without validating the constraints. As an extreme
    example, when the application is started with a clean DB a large
    number of nmm:Photo objects are added by the miners. We end up
    displaying a huge number of items in the GtkIconView and chewing 100%
    CPU.
    
    We should do better.
    
    For starters, let us not add new items to the model if:
     - The number of rows in the model is equal to the sum of the current
       step and offset, AND
     - The item is older than the oldest item currently in the model
    
    We could still have more rows in the model than stipulated by the
    current step and offset if the item being added is recent enough. If
    the current filtering proves to be insufficient then we can look into
    removing older rows from the model as newer ones are added.
    
    Also, update the count in PhotosOffsetController whenever a new item
    is added so that things like the the "Load More" button works
    correctly.
    
    Fixes: https://bugzilla.gnome.org/721402

 src/photos-view-model.c |  130 ++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 122 insertions(+), 8 deletions(-)
---
diff --git a/src/photos-view-model.c b/src/photos-view-model.c
index 274fc64..fb1444d 100644
--- a/src/photos-view-model.c
+++ b/src/photos-view-model.c
@@ -1,6 +1,6 @@
 /*
  * Photos - access, organize and share your photos on GNOME
- * Copyright © 2012, 2013 Red Hat, Inc.
+ * Copyright © 2012, 2013, 2014 Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -28,6 +28,9 @@
 #include "photos-collection-manager.h"
 #include "photos-enums.h"
 #include "photos-item-manager.h"
+#include "photos-offset-collections-controller.h"
+#include "photos-offset-favorites-controller.h"
+#include "photos-offset-overview-controller.h"
 #include "photos-view-model.h"
 
 
@@ -35,8 +38,12 @@ struct _PhotosViewModelPrivate
 {
   PhotosBaseManager *col_mngr;
   PhotosBaseManager *item_mngr;
+  PhotosOffsetController *offset_cntrlr;
   PhotosWindowMode mode;
   gchar *row_ref_key;
+  gint n_rows;
+  gint64 oldest_mtime;
+  guint reset_count_id;
 };
 
 enum
@@ -49,6 +56,12 @@ enum
 G_DEFINE_TYPE_WITH_PRIVATE (PhotosViewModel, photos_view_model, GTK_TYPE_LIST_STORE);
 
 
+enum
+{
+  RESET_COUNT_TIMEOUT = 500 /* ms */
+};
+
+
 static void
 photos_view_model_info_set (PhotosViewModel *self, PhotosBaseItem *item, GtkTreeIter *iter)
 {
@@ -64,16 +77,53 @@ photos_view_model_info_set (PhotosViewModel *self, PhotosBaseItem *item, GtkTree
 }
 
 
+static gboolean
+photos_view_model_reset_count_timeout (gpointer user_data)
+{
+  PhotosViewModel *self = PHOTOS_VIEW_MODEL (user_data);
+  PhotosViewModelPrivate *priv = self->priv;
+
+  priv->reset_count_id = 0;
+  photos_offset_controller_reset_count (priv->offset_cntrlr);
+  return G_SOURCE_REMOVE;
+}
+
+
 static void
 photos_view_model_add_item (PhotosViewModel *self, PhotosBaseItem *item)
 {
+  PhotosViewModelPrivate *priv = self->priv;
   GtkTreeIter iter;
   GtkTreePath *path;
   GtkTreeRowReference *row_ref;
+  gint offset;
+  gint step;
+  gint64 mtime;
+
+  /* Update the count so that PhotosOffsetController has the correct
+   * values. Otherwise things like the "Load More" button will not
+   * work correctly.
+   */
+  if (priv->reset_count_id == 0)
+    priv->reset_count_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
+                                               RESET_COUNT_TIMEOUT,
+                                               photos_view_model_reset_count_timeout,
+                                               g_object_ref (self),
+                                               g_object_unref);
+
+  offset = photos_offset_controller_get_offset (priv->offset_cntrlr);
+  step = photos_offset_controller_get_step (priv->offset_cntrlr);
+  mtime = photos_base_item_get_mtime (item);
+  if (priv->n_rows >= offset + step && mtime < priv->oldest_mtime)
+    return;
 
   gtk_list_store_append (GTK_LIST_STORE (self), &iter);
   photos_view_model_info_set (self, item, &iter);
 
+  priv->n_rows++;
+  if (mtime < priv->oldest_mtime)
+    priv->oldest_mtime = mtime;
+
   path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), &iter);
   row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (self), path);
   gtk_tree_path_free (path);
@@ -85,25 +135,48 @@ photos_view_model_add_item (PhotosViewModel *self, PhotosBaseItem *item)
 }
 
 
+static void
+photos_view_model_clear (PhotosViewModel *self)
+{
+  PhotosViewModelPrivate *priv = self->priv;
+
+  gtk_list_store_clear (GTK_LIST_STORE (self));
+  priv->n_rows = 0;
+  priv->oldest_mtime = G_MAXINT64;
+}
+
+
 static gboolean
 photos_view_model_item_removed_foreach (GtkTreeModel *model,
                                         GtkTreePath *path,
                                         GtkTreeIter *iter,
                                         gpointer user_data)
 {
+  PhotosViewModel *self = PHOTOS_VIEW_MODEL (model);
+  PhotosViewModelPrivate *priv = self->priv;
   PhotosBaseItem *item = PHOTOS_BASE_ITEM (user_data);
   gboolean ret_val = FALSE;
   const gchar *id;
   gchar *value;
+  gint64 mtime;
 
   id = photos_base_item_get_id (item);
-  gtk_tree_model_get (model, iter, PHOTOS_VIEW_MODEL_URN, &value, -1);
+  gtk_tree_model_get (model, iter, PHOTOS_VIEW_MODEL_URN, &value, PHOTOS_VIEW_MODEL_MTIME, &mtime, -1);
 
   if (g_strcmp0 (id, value) == 0)
     {
+      GtkTreeIter tmp;
+
+      tmp = *iter;
+      if (!gtk_tree_model_iter_next (model, &tmp))
+        ret_val = TRUE;
+
       gtk_list_store_remove (GTK_LIST_STORE (model), iter);
-      ret_val = TRUE;
+      gtk_tree_path_next (path); /* Ensure that path in sync with iter. */
+      priv->n_rows--;
     }
+  else if (mtime < priv->oldest_mtime)
+    priv->oldest_mtime = mtime;
 
   g_free (value);
   return ret_val;
@@ -113,10 +186,12 @@ photos_view_model_item_removed_foreach (GtkTreeModel *model,
 static void
 photos_view_model_object_removed (PhotosViewModel *self, GObject *object)
 {
+  PhotosViewModelPrivate *priv = self->priv;
   PhotosBaseItem *item = PHOTOS_BASE_ITEM (object);
 
+  priv->oldest_mtime = G_MAXINT64;
   gtk_tree_model_foreach (GTK_TREE_MODEL (self), photos_view_model_item_removed_foreach, item);
-  g_object_set_data (object, self->priv->row_ref_key, NULL);
+  g_object_set_data (object, priv->row_ref_key, NULL);
 }
 
 
@@ -206,13 +281,53 @@ photos_view_model_object_added (PhotosViewModel *self, GObject *object)
 
 
 static void
+photos_view_model_constructed (GObject *object)
+{
+  PhotosViewModel *self = PHOTOS_VIEW_MODEL (object);
+  PhotosViewModelPrivate *priv = self->priv;
+
+  G_OBJECT_CLASS (photos_view_model_parent_class)->constructed (object);
+
+  switch (priv->mode)
+    {
+    case PHOTOS_WINDOW_MODE_COLLECTIONS:
+      priv->offset_cntrlr = photos_offset_collections_controller_dup_singleton ();
+      break;
+
+    case PHOTOS_WINDOW_MODE_FAVORITES:
+      priv->offset_cntrlr = photos_offset_favorites_controller_dup_singleton ();
+      break;
+
+    case PHOTOS_WINDOW_MODE_OVERVIEW:
+      priv->offset_cntrlr = photos_offset_overview_controller_dup_singleton ();
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  g_signal_connect_swapped (priv->item_mngr, "object-added", G_CALLBACK (photos_view_model_object_added), 
self);
+  g_signal_connect_swapped (priv->item_mngr, "object-removed", G_CALLBACK 
(photos_view_model_object_removed), self);
+  g_signal_connect_swapped (priv->item_mngr, "clear", G_CALLBACK (photos_view_model_clear), self);
+}
+
+
+static void
 photos_view_model_dispose (GObject *object)
 {
   PhotosViewModel *self = PHOTOS_VIEW_MODEL (object);
   PhotosViewModelPrivate *priv = self->priv;
 
+  if (priv->reset_count_id != 0)
+    {
+      g_source_remove (priv->reset_count_id);
+      priv->reset_count_id = 0;
+    }
+
   g_clear_object (&priv->col_mngr);
   g_clear_object (&priv->item_mngr);
+  g_clear_object (&priv->offset_cntrlr);
 
   G_OBJECT_CLASS (photos_view_model_parent_class)->dispose (object);
 }
@@ -268,11 +383,9 @@ photos_view_model_init (PhotosViewModel *self)
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self), PHOTOS_VIEW_MODEL_MTIME, 
GTK_SORT_DESCENDING);
 
   priv->col_mngr = photos_collection_manager_dup_singleton ();
-
   priv->item_mngr = photos_item_manager_dup_singleton ();
-  g_signal_connect_swapped (priv->item_mngr, "object-added", G_CALLBACK (photos_view_model_object_added), 
self);
-  g_signal_connect_swapped (priv->item_mngr, "object-removed", G_CALLBACK 
(photos_view_model_object_removed), self);
-  g_signal_connect_swapped (priv->item_mngr, "clear", G_CALLBACK (gtk_list_store_clear), self);
+
+  priv->oldest_mtime = G_MAXINT64;
 }
 
 
@@ -281,6 +394,7 @@ photos_view_model_class_init (PhotosViewModelClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
+  object_class->constructed = photos_view_model_constructed;
   object_class->dispose = photos_view_model_dispose;
   object_class->finalize = photos_view_model_finalize;
   object_class->set_property = photos_view_model_set_property;


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