[evince/wip/recent-view: 3/12] bookshelf: Save thumbnails and metadata



commit b7965523f13b09336d40b479ba293b60e5c4324c
Author: Aakash Goenka <aakash goenka gmail com>
Date:   Sun Feb 23 15:38:33 2014 -0800

    bookshelf: Save thumbnails and metadata
    
    Use gtk_recent_info_get_modified instead of
    gtk_recent_info_get_visited for ordering the recent items.

 shell/ev-bookshelf.c |  186 ++++++++++++++++++++++++++++++++++++++++++--------
 shell/ev-metadata.c  |   33 +++++++++
 shell/ev-metadata.h  |    6 ++
 3 files changed, 196 insertions(+), 29 deletions(-)
---
diff --git a/shell/ev-bookshelf.c b/shell/ev-bookshelf.c
index 934ccae..7173c6c 100644
--- a/shell/ev-bookshelf.c
+++ b/shell/ev-bookshelf.c
@@ -22,6 +22,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include "ev-bookshelf.h"
+#include "ev-file-helpers.h"
 #include "gd-icon-utils.h"
 #include "gd-main-view-generic.h"
 #include "gd-main-icon-view.h"
@@ -29,17 +30,20 @@
 #include "ev-document-model.h"
 #include "ev-jobs.h"
 #include "ev-job-scheduler.h"
+#include "ev-metadata.h"
 
 typedef enum {
        EV_BOOKSHELF_JOB_COLUMN = GD_MAIN_COLUMN_LAST,
        EV_BOOKSHELF_THUMBNAILED_COLUMN,
        EV_BOOKSHELF_DOCUMENT_COLUMN,
+       EV_BOOKSHELF_METADATA_COLUMN,
        NUM_COLUMNS
 } EvBookshelfColumns;
 
 struct _EvBookshelfPrivate {
        GtkWidget         *view;
        GtkListStore      *list_store;
+       GtkRecentManager  *recent_manager;
        gchar             *button_press_item_path;
 };
 
@@ -59,11 +63,12 @@ static gboolean ev_bookshelf_clear_job                   (GtkTreeModel *model,
                                                           GtkTreeIter  *iter,
                                                           gpointer     data);
 static void     ev_bookshelf_clear_model                 (EvBookshelf *bookshelf);
+static void     ev_bookshelf_refresh                     (EvBookshelf *bookshelf);
 
 G_DEFINE_TYPE (EvBookshelf, ev_bookshelf, GTK_TYPE_SCROLLED_WINDOW)
 
 #define ICON_VIEW_SIZE 128
-#define MAX_RECENT_ITEMS 20
+#define MAX_BOOKSHELF_ITEMS 20
 
 static void
 ev_bookshelf_dispose (GObject *obj)
@@ -76,10 +81,75 @@ ev_bookshelf_dispose (GObject *obj)
                self->priv->list_store = NULL;
        }
 
+       if (self->priv->recent_manager) {
+               g_signal_handlers_disconnect_by_func (self->priv->recent_manager,
+                                                     ev_bookshelf_refresh,
+                                                     self);
+               self->priv->recent_manager = NULL;
+       }
        G_OBJECT_CLASS (ev_bookshelf_parent_class)->dispose (obj);
 }
 
 static gboolean
+metadata_is_stale (EvMetadata *metadata,
+                   GFile      *file)
+{
+       GFileInfo *info = NULL;
+       GError    *error = NULL;
+       guint64    mtime_metadata;
+       guint64    mtime_file;
+
+       info = g_file_query_info (file,
+                                 G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                 0,
+                                 NULL,
+                                 &error);
+       if (!info) {
+               g_warning ("%s", error->message);
+               g_error_free (error);
+
+               return TRUE;
+       }
+
+       if (!ev_metadata_get_uint64 (metadata, "mtime", &mtime_metadata))
+               return TRUE;
+
+       mtime_file = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+       if (mtime_file != 0 && mtime_metadata >= mtime_file)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+save_thumbnail (GdkPixbuf  *pixbuf,
+                EvMetadata *metadata)
+{
+       GFile     *thumbnail_file = NULL;
+       GError    *error = NULL;
+       gchar     *thumbnail_path = NULL;
+
+       thumbnail_file = ev_mkstemp_file ("thumb.XXXXXX", &error);
+
+       if (thumbnail_file) {
+               thumbnail_path = g_file_get_path (thumbnail_file);
+               g_object_unref (thumbnail_file);
+       }
+
+       if (thumbnail_path) {
+               gdk_pixbuf_save (pixbuf, thumbnail_path,
+                                "png", &error, NULL);
+               if (!error)
+                       ev_metadata_set_string (metadata, "thumbnail-path", thumbnail_path);
+               g_free (thumbnail_path);
+       }
+
+       if (error)
+               g_error_free (error);
+}
+
+static gboolean
 ev_bookshelf_clear_job (GtkTreeModel *model,
                         GtkTreePath *path,
                         GtkTreeIter *iter,
@@ -121,8 +191,8 @@ compare_recent_items (GtkRecentInfo *a,
        if (has_ev_a && has_ev_b) {
                time_t time_a, time_b;
 
-               time_a = gtk_recent_info_get_added (a);
-               time_b = gtk_recent_info_get_added (b);
+               time_a = gtk_recent_info_get_modified (a);
+               time_b = gtk_recent_info_get_modified (b);
 
                return (time_b - time_a);
        } else if (has_ev_a) {
@@ -186,6 +256,10 @@ on_button_release_event (GtkWidget      *view,
                gtk_tree_model_get (GTK_TREE_MODEL (self->priv->list_store), &iter,
                                    GD_MAIN_COLUMN_URI, &uri,
                                    -1);
+               gtk_list_store_set (self->priv->list_store,
+                                   &iter,
+                                   GD_MAIN_COLUMN_SELECTED, TRUE,
+                                   -1);
                g_signal_emit (self, signals[ITEM_ACTIVATED], 0, uri);
        }
     exit:
@@ -219,7 +293,8 @@ thumbnail_job_completed_callback (EvJobThumbnail *job,
        EvBookshelfPrivate *priv = ev_bookshelf->priv;
        GtkTreeIter        *iter;
        GdkPixbuf          *pixbuf;
-       EvDocument          document;
+       EvDocument         *document;
+       EvMetadata         *metadata;
        GtkBorder           border;
 
        border.left = 4;
@@ -237,6 +312,7 @@ thumbnail_job_completed_callback (EvJobThumbnail *job,
        gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store),
                            iter,
                            EV_BOOKSHELF_DOCUMENT_COLUMN, &document,
+                           EV_BOOKSHELF_METADATA_COLUMN, &metadata,
                            -1);
 
        gtk_list_store_set (priv->list_store,
@@ -246,6 +322,11 @@ thumbnail_job_completed_callback (EvJobThumbnail *job,
                            EV_BOOKSHELF_JOB_COLUMN, NULL,
                            -1);
 
+       if (metadata) {
+               save_thumbnail (pixbuf, metadata);
+               ev_metadata_set_uint64 (metadata, "mtime", g_get_real_time ());
+               g_object_unref (metadata);
+       }
         g_object_unref (pixbuf);
 }
 
@@ -256,6 +337,7 @@ document_load_job_completed_callback (EvJobLoad   *job_load,
        EvBookshelfPrivate *priv = ev_bookshelf->priv;
        GtkTreeIter        *iter;
        EvDocument         *document;
+       EvMetadata         *metadata;
 
        document = EV_JOB (job_load)->document;
        iter = (GtkTreeIter *) g_object_get_data (G_OBJECT (job_load), "tree_iter");
@@ -288,17 +370,39 @@ document_load_job_completed_callback (EvJobLoad   *job_load,
                                    EV_BOOKSHELF_JOB_COLUMN, job_thumbnail,
                                    EV_BOOKSHELF_DOCUMENT_COLUMN, document,
                                    -1);
-               
+
                ev_job_scheduler_push_job (EV_JOB (job_thumbnail), EV_JOB_PRIORITY_HIGH);
 
                g_object_unref (job_thumbnail);
 
        } else {
+               gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store),
+                                   iter,
+                                   EV_RECENT_VIEW_METADATA_COLUMN, &metadata,
+                                   -1);
+
                gtk_list_store_set (priv->list_store,
                                    iter,
                                    EV_BOOKSHELF_THUMBNAILED_COLUMN, TRUE,
                                    EV_BOOKSHELF_JOB_COLUMN, NULL,
                                    -1);
+
+               if (metadata) {
+                       GdkPixbuf *thumbnail;
+
+                       gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store),
+                                           iter,
+                                           GD_MAIN_COLUMN_ICON, &thumbnail,
+                                           -1);
+
+                       if (thumbnail)
+                               save_thumbnail (thumbnail, metadata);
+
+                       ev_metadata_set_uint64 (metadata, "mtime", g_get_real_time ());
+
+                       g_object_unref (metadata);
+                       g_object_unref (thumbnail);
+               }
        }
 }
 
@@ -308,18 +412,20 @@ ev_bookshelf_refresh (EvBookshelf *ev_bookshelf)
        GList             *items, *l;
        guint              n_items = 0;
        const gchar       *evince = g_get_application_name ();
-       GtkRecentManager  *recent_manager = gtk_recent_manager_get_default ();
        GdMainViewGeneric *generic = get_generic (ev_bookshelf);
 
-       items = gtk_recent_manager_get_items (recent_manager);
+       items = gtk_recent_manager_get_items (ev_bookshelf->priv->recent_manager);
        items = g_list_sort (items, (GCompareFunc) compare_recent_items);
 
        gtk_list_store_clear (ev_bookshelf->priv->list_store);
 
        for (l = items; l && l->data; l = g_list_next (l)) {
-               EvJob         *job_load;
+               EvJob         *job_load = NULL;
+               EvMetadata    *metadata = NULL;
+               GFile         *file;
                const gchar   *name;
                const gchar   *uri;
+               gchar         *thumbnail_path;
                GtkRecentInfo *info;
                GdkPixbuf     *thumbnail;
                GtkTreeIter    iter;
@@ -332,47 +438,63 @@ ev_bookshelf_refresh (EvBookshelf *ev_bookshelf)
 
                name = gtk_recent_info_get_display_name (info);
                uri = gtk_recent_info_get_uri (info);
-
-               thumbnail = gtk_recent_info_get_icon (info, ICON_VIEW_SIZE);
-
-               job_load = ev_job_load_new (uri);
-
-               g_signal_connect (job_load, "finished",
-                                 G_CALLBACK (document_load_job_completed_callback),
-                                 ev_bookshelf);
-
-               access_time = gtk_recent_info_get_added (info);
+               file = g_file_new_for_uri (uri);
+
+               if (ev_is_metadata_supported_for_file (file)) {
+                       
+                       metadata = ev_metadata_new (file);
+                       if (metadata_is_stale (metadata, file) ||
+                           !ev_metadata_get_string (metadata, "thumbnail-path", &thumbnail_path))
+                               goto load_document;
+
+                       thumbnail = gdk_pixbuf_new_from_file (thumbnail_path, NULL);
+                       if (!thumbnail)
+                               goto load_document;
+               } else {
+
+               load_document:
+
+                       thumbnail = gtk_recent_info_get_icon (info, ICON_VIEW_SIZE);
+                       job_load = ev_job_load_new (uri);
+                       g_signal_connect (job_load, "finished",
+                                         G_CALLBACK (document_load_job_completed_callback),
+                                         ev_bookshelf);
+               }
+               access_time = gtk_recent_info_get_modified (info);
 
                gtk_list_store_append (ev_bookshelf->priv->list_store, &iter);
 
                gtk_list_store_set (ev_bookshelf->priv->list_store, &iter,
                                    GD_MAIN_COLUMN_URI, uri,
                                    GD_MAIN_COLUMN_PRIMARY_TEXT, name,
-                                   GD_MAIN_COLUMN_SECONDARY_TEXT, _(""),
+                                   GD_MAIN_COLUMN_SECONDARY_TEXT, NULL,
                                    GD_MAIN_COLUMN_ICON, thumbnail,
                                    GD_MAIN_COLUMN_MTIME, access_time,
                                    GD_MAIN_COLUMN_SELECTED, FALSE,
                                    EV_BOOKSHELF_DOCUMENT_COLUMN, NULL,
                                    EV_BOOKSHELF_JOB_COLUMN, job_load,
                                    EV_BOOKSHELF_THUMBNAILED_COLUMN, FALSE,
+                                   EV_BOOKSHELF_METADATA_COLUMN, metadata,
                                    -1);
 
-               g_object_set_data_full (G_OBJECT (job_load), "tree_iter",
-                                       gtk_tree_iter_copy (&iter),
-                                       (GDestroyNotify) gtk_tree_iter_free);
-
-               ev_job_scheduler_push_job (EV_JOB (job_load), EV_JOB_PRIORITY_HIGH);
+               if (job_load) {
+                       
+                       g_object_set_data_full (G_OBJECT (job_load), "tree_iter",
+                                               gtk_tree_iter_copy (&iter),
+                                               (GDestroyNotify) gtk_tree_iter_free);
 
+                       ev_job_scheduler_push_job (EV_JOB (job_load), EV_JOB_PRIORITY_HIGH);
+               }
                if (thumbnail != NULL)
                         g_object_unref (thumbnail);
 
-               if (++n_items == MAX_RECENT_ITEMS)
+               if (++n_items == MAX_BOOKSHELF_ITEMS)
                        break;
        }
-       
+
        g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
        g_list_free (items);
-       
+
        gd_main_view_generic_set_model (generic, GTK_TREE_MODEL (ev_bookshelf->priv->list_store));
 }
 
@@ -415,7 +537,8 @@ static void
 ev_bookshelf_init (EvBookshelf *ev_bookshelf)
 {
        ev_bookshelf->priv = G_TYPE_INSTANCE_GET_PRIVATE (ev_bookshelf, EV_TYPE_BOOKSHELF, 
EvBookshelfPrivate);
-       ev_bookshelf->priv->list_store = gtk_list_store_new (10,
+       ev_bookshelf->priv->recent_manager = gtk_recent_manager_get_default ();
+       ev_bookshelf->priv->list_store = gtk_list_store_new (11,
                                                             G_TYPE_STRING,
                                                             G_TYPE_STRING,
                                                             G_TYPE_STRING,
@@ -425,7 +548,8 @@ ev_bookshelf_init (EvBookshelf *ev_bookshelf)
                                                             G_TYPE_BOOLEAN,
                                                             EV_TYPE_JOB,
                                                             G_TYPE_BOOLEAN,
-                                                            EV_TYPE_DOCUMENT);
+                                                            EV_TYPE_DOCUMENT,
+                                                            EV_TYPE_METADATA);
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (ev_bookshelf->priv->list_store),
                                              GD_MAIN_COLUMN_MTIME,
                                              GTK_SORT_DESCENDING);
@@ -437,6 +561,10 @@ ev_bookshelf_init (EvBookshelf *ev_bookshelf)
                                        GTK_POLICY_NEVER,
                                        GTK_POLICY_AUTOMATIC);
 
+       g_signal_connect_swapped (ev_bookshelf->priv->recent_manager,
+                                 "changed",
+                                 G_CALLBACK (ev_bookshelf_refresh),
+                                 ev_bookshelf);
 }
 
 static void
diff --git a/shell/ev-metadata.c b/shell/ev-metadata.c
index b0e23a1..52e40c1 100644
--- a/shell/ev-metadata.c
+++ b/shell/ev-metadata.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include <glib.h>
 #include <gio/gio.h>
 #include <string.h>
 
@@ -229,6 +230,26 @@ ev_metadata_get_int (EvMetadata  *metadata,
 }
 
 gboolean
+ev_metadata_get_uint64 (EvMetadata  *metadata,
+                        const gchar *key,
+                        guint64     *value)
+{
+       gchar   *string_value;
+       gchar   *endptr;
+       guint64  uint64_value;
+
+       if (!ev_metadata_get_string (metadata, key, &string_value))
+               return FALSE;
+
+       uint64_value = g_ascii_strtoull (string_value, &endptr, 0);
+       if (uint64_value == 0 && string_value == endptr)
+               return FALSE;
+
+       *value = uint64_value;
+       return TRUE;
+}
+
+gboolean
 ev_metadata_set_int (EvMetadata  *metadata,
                     const gchar *key,
                     gint         value)
@@ -241,6 +262,18 @@ ev_metadata_set_int (EvMetadata  *metadata,
 }
 
 gboolean
+ev_metadata_set_uint64 (EvMetadata  *metadata,
+                       const gchar *key,
+                       guint64      value)
+{
+       gchar string_value[21];
+
+       g_snprintf (string_value, sizeof (string_value), "%"G_GUINT64_FORMAT, value);
+
+       return ev_metadata_set_string (metadata, key, string_value);
+}
+
+gboolean
 ev_metadata_get_double (EvMetadata  *metadata,
                        const gchar *key,
                        gdouble     *value)
diff --git a/shell/ev-metadata.h b/shell/ev-metadata.h
index 7fd4f05..ba31069 100644
--- a/shell/ev-metadata.h
+++ b/shell/ev-metadata.h
@@ -62,6 +62,12 @@ gboolean    ev_metadata_get_boolean           (EvMetadata  *metadata,
 gboolean    ev_metadata_set_boolean           (EvMetadata  *metadata,
                                               const gchar *key,
                                               gboolean     value);
+gboolean    ev_metadata_get_uint64            (EvMetadata  *metadata,
+                                               const gchar *key,
+                                               guint64     *value);
+gboolean    ev_metadata_set_uint64            (EvMetadata  *metadata,
+                                              const gchar *key,
+                                              guint64      value);
 gboolean    ev_metadata_has_key               (EvMetadata  *metadata,
                                                const gchar *key);
 


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