[gnome-video-arcade] Add a "Last Played" column.



commit 4bc7233c0f09e88d645b3809fb1871430dd0c7da
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Jan 10 23:28:59 2010 -0500

    Add a "Last Played" column.
    
    The "Last Played" column shows a timestamp indicating when emulation of
    the game was last terminated.  If the timestamp is for the current date,
    only the time is shown.  Otherwise only the date is shown.  Sorting the
    column remains accurate, however.

 docs/reference/tmpl/gva-game-store.sgml |    1 +
 src/gva-columns.c                       |   50 +++++++++++++++++++++++--
 src/gva-db.c                            |   11 +++++-
 src/gva-game-store.c                    |   11 +++++
 src/gva-game-store.h                    |    3 +
 src/gva-tree-view.c                     |    2 +-
 src/gva-ui.c                            |   62 ++++++++++++++++++++++++++++++-
 7 files changed, 132 insertions(+), 8 deletions(-)
---
diff --git a/docs/reference/tmpl/gva-game-store.sgml b/docs/reference/tmpl/gva-game-store.sgml
index 9a7a678..e3337cd 100644
--- a/docs/reference/tmpl/gva-game-store.sgml
+++ b/docs/reference/tmpl/gva-game-store.sgml
@@ -60,6 +60,7 @@
 @GVA_GAME_STORE_COLUMN_DRIVER_PROTECTION: 
 @GVA_GAME_STORE_COLUMN_DRIVER_SAVESTATE: 
 @GVA_GAME_STORE_COLUMN_DRIVER_PALETTESIZE: 
+ GVA_GAME_STORE_COLUMN_LAST_PLAYED: 
 @GVA_GAME_STORE_COLUMN_COMMENT: 
 @GVA_GAME_STORE_COLUMN_INODE: 
 @GVA_GAME_STORE_COLUMN_INPFILE: 
diff --git a/src/gva-columns.c b/src/gva-columns.c
index f85d2f8..dcccafe 100644
--- a/src/gva-columns.c
+++ b/src/gva-columns.c
@@ -244,15 +244,34 @@ columns_time_set_properties (GtkTreeViewColumn *column,
 {
         GvaGameStoreColumn column_id;
         GValue value;
-        gchar text[256];
+        gchar text[256] = { '\0' };
+        time_t *time_ptr;
 
         memset (&value, 0, sizeof (GValue));
         column_id = gtk_tree_view_column_get_sort_column_id (column);
         gtk_tree_model_get_value (model, iter, column_id, &value);
 
-        strftime (
-                text, sizeof (text), nl_langinfo (D_T_FMT),
-                localtime (g_value_get_boxed (&value)));
+        time_ptr = g_value_get_boxed (&value);
+
+        /* Render epoch values as empty cells. */
+        if (*time_ptr > (time_t) 0)
+        {
+                GDate date, today;
+                gboolean date_is_today;
+
+                g_date_clear (&date, 1);
+                g_date_clear (&today, 1);
+
+                g_date_set_time_t (&date, *time_ptr);
+                g_date_set_time_t (&today, time (NULL));
+
+                date_is_today = (g_date_compare (&date, &today) == 0);
+
+                strftime (
+                        text, sizeof (text),
+                        nl_langinfo (date_is_today ? T_FMT : D_FMT),
+                        localtime (time_ptr));
+        }
 
         g_object_set (renderer, "text", text, NULL);
 
@@ -525,6 +544,26 @@ columns_factory_input_players_sim (GvaGameStoreColumn column_id)
 }
 
 static GtkTreeViewColumn *
+columns_factory_lastplayed (GvaGameStoreColumn column_id)
+{
+        GtkTreeViewColumn *column;
+        GtkCellRenderer *renderer;
+
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_reorderable (column, TRUE);
+        gtk_tree_view_column_set_sort_column_id (column, column_id);
+
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+        gtk_tree_view_column_set_cell_data_func (
+                column, renderer, (GtkTreeCellDataFunc)
+                columns_time_set_properties, NULL, NULL);
+
+        return column;
+}
+
+static GtkTreeViewColumn *
 columns_factory_manufacturer (GvaGameStoreColumn column_id)
 {
         GtkTreeViewColumn *column;
@@ -996,6 +1035,8 @@ column_info[GVA_GAME_STORE_NUM_COLUMNS] =
         { "driver_protection",  NULL },
         { "driver_savestate",   NULL },
         { "driver_palettesize", NULL },
+        { "lastplayed",         N_("Last Played"),
+                                columns_factory_lastplayed },
         { "comment",            N_("Comment"),
                                 columns_factory_comment },
         { "inode",              NULL },
@@ -1013,6 +1054,7 @@ static gchar *default_column_order[] =
 #ifdef CATEGORY_FILE
         "category",
 #endif
+        "lastplayed",
         "bios",
         "driver_status",
         "input_players",
diff --git a/src/gva-db.c b/src/gva-db.c
index 36f0551..f105460 100644
--- a/src/gva-db.c
+++ b/src/gva-db.c
@@ -199,6 +199,12 @@
                 "name NOT NULL, " \
                 "default_ NOT NULL);"
 
+/* The lastplayed table survives database builds. */
+#define SQL_CREATE_TABLE_LASTPLAYED \
+        "CREATE TABLE IF NOT EXISTS lastplayed (" \
+                "name PRIMARY KEY ON CONFLICT REPLACE, " \
+                "timestamp);"
+
 /* The playback table survives database builds. */
 #define SQL_CREATE_TABLE_PLAYBACK \
         "CREATE TABLE IF NOT EXISTS playback (" \
@@ -219,7 +225,9 @@
 #define SQL_CREATE_VIEW_AVAILABLE \
         "CREATE VIEW IF NOT EXISTS available AS " \
                 "SELECT game.*, bios.description AS bios, " \
-                "isfavorite(game.name) AS favorite FROM game " \
+                "isfavorite(game.name) AS favorite, " \
+                "lastplayed.timestamp AS lastplayed " \
+                "FROM game LEFT JOIN lastplayed USING (name) " \
                 "LEFT JOIN (SELECT name, description FROM game WHERE " \
                 "isbios = 'yes') AS bios ON game.romof = bios.name " \
                 "WHERE (romset IN ('good', 'best available') " \
@@ -1508,6 +1516,7 @@ db_create_tables (GError **error)
                 && gva_db_execute (SQL_CREATE_TABLE_DISPLAY, error)
                 && gva_db_execute (SQL_CREATE_TABLE_CONTROL, error)
                 && gva_db_execute (SQL_CREATE_TABLE_DIPVALUE, error)
+                && gva_db_execute (SQL_CREATE_TABLE_LASTPLAYED, error)
                 && gva_db_execute (SQL_CREATE_TABLE_PLAYBACK, error)
                 && gva_db_execute (SQL_CREATE_TABLE_WINDOW, error)
                 && gva_db_execute (SQL_CREATE_VIEW_AVAILABLE, error);
diff --git a/src/gva-game-store.c b/src/gva-game-store.c
index 61f5dc9..df0e688 100644
--- a/src/gva-game-store.c
+++ b/src/gva-game-store.c
@@ -153,6 +153,7 @@ game_store_constructor (GType type,
         types[column++] = G_TYPE_STRING;     /* COLUMN_DRIVER_PROTECTION */
         types[column++] = G_TYPE_STRING;     /* COLUMN_DRIVER_SAVESTATE */
         types[column++] = G_TYPE_INT;        /* COLUMN_DRIVER_PALETTESIZE */
+        types[column++] = GVA_TYPE_TIME;     /* COLUMN_LAST_PLAYED */
         types[column++] = G_TYPE_STRING;     /* COLUMN_COMMENT */
         types[column++] = G_TYPE_INT64;      /* COLUMN_INODE */
         types[column++] = G_TYPE_STRING;     /* COLUMN_INPFILE */
@@ -370,6 +371,16 @@ gva_game_store_new_from_query (const gchar *sql,
                                         v_string = "";
                                 g_value_set_string (value, v_string);
                         }
+                        else if (type == GVA_TYPE_TIME)
+                        {
+                                sqlite3_int64 v_int64;
+                                time_t v_time;
+
+                                /* XXX Is this widely portable? */
+                                v_int64 = sqlite3_column_int64 (stmt, ii);
+                                v_time = (time_t) v_int64;
+                                g_value_set_boxed (value, &v_time);
+                        }
                         else
                         {
                                 g_assert_not_reached ();
diff --git a/src/gva-game-store.h b/src/gva-game-store.h
index cbf4f70..50e4769 100644
--- a/src/gva-game-store.h
+++ b/src/gva-game-store.h
@@ -119,6 +119,8 @@ typedef struct _GvaGameStoreClass GvaGameStoreClass;
  *      Corresponds to the "available.driver_savestate" database field.
  * @GVA_GAME_STORE_COLUMN_DRIVER_PALETTESIZE:
  *      Corresponds to the "available.driver_palettesize" database field.
+ * @GVA_GAME_STORE_COLUMN_LAST_PLAYED:
+ *      Corresponds to the "lastplayed.timestamp" database field.
  * @GVA_GAME_STORE_COLUMN_COMMENT:
  *      Corresponds to the "playback.comment" database field.
  * @GVA_GAME_STORE_COLUMN_INODE:
@@ -166,6 +168,7 @@ typedef enum
         GVA_GAME_STORE_COLUMN_DRIVER_PROTECTION,  /* G_TYPE_STRING */
         GVA_GAME_STORE_COLUMN_DRIVER_SAVESTATE,   /* G_TYPE_STRING */
         GVA_GAME_STORE_COLUMN_DRIVER_PALETTESIZE, /* G_TYPE_INT */
+        GVA_GAME_STORE_COLUMN_LAST_PLAYED,        /* GVA_TYPE_TIME */
         GVA_GAME_STORE_COLUMN_COMMENT,            /* G_TYPE_STRING */
         GVA_GAME_STORE_COLUMN_INODE,              /* G_TYPE_INT64 */
         GVA_GAME_STORE_COLUMN_INPFILE,            /* G_TYPE_STRING */
diff --git a/src/gva-tree-view.c b/src/gva-tree-view.c
index c03c8c0..29a9487 100644
--- a/src/gva-tree-view.c
+++ b/src/gva-tree-view.c
@@ -330,7 +330,7 @@ gva_tree_view_run_query (const gchar *expression,
         model = gva_game_store_new_from_query (string->str, error);
 
         /* Don't touch widgets if gtk_main_quit() has been called. */
-        if (!gtk_main_iteration_do (FALSE))
+        if (model != NULL && !gtk_main_iteration_do (FALSE))
         {
                 sensitive = (gtk_tree_model_iter_n_children (model, NULL) > 0);
                 gtk_widget_set_sensitive (GTK_WIDGET (view), sensitive);
diff --git a/src/gva-ui.c b/src/gva-ui.c
index 8102562..b32883e 100644
--- a/src/gva-ui.c
+++ b/src/gva-ui.c
@@ -20,6 +20,7 @@
 
 #include "gva-audit.h"
 #include "gva-column-manager.h"
+#include "gva-db.h"
 #include "gva-error.h"
 #include "gva-favorites.h"
 #include "gva-game-store.h"
@@ -37,6 +38,9 @@
 #include "gva-dbus.h"
 #endif
 
+#define SQL_INSERT_LASTPLAYED \
+        "INSERT INTO lastplayed VALUES ('%s', %" G_GINT64_FORMAT ")"
+
 static GtkBuilder *builder = NULL;
 static GtkUIManager *manager = NULL;
 static GtkActionGroup *action_group = NULL;
@@ -65,6 +69,47 @@ static const gchar *license =
 "along with this program.  If not, see <http://www.gnu.org/licenses/>.";
 
 static void
+log_lastplayed (GvaProcess *process,
+                gint status,
+                gchar *name)
+{
+        GtkTreePath *path;
+        gchar *sql;
+        time_t now;
+        GError *error = NULL;
+
+        if (process->error != NULL)
+                return;
+
+        time (&now);
+
+        /* Record the time in the database. */
+        sql = g_strdup_printf (SQL_INSERT_LASTPLAYED, name, (gint64) now);
+        gva_db_execute (sql, &error);
+        gva_error_handle (&error);
+        g_free (sql);
+
+        /* Record the time in the tree model. */
+        path = gva_tree_view_lookup (name);
+        if (path != NULL)
+        {
+                GtkTreeModel *model;
+                GtkTreeIter iter;
+
+                model = gva_tree_view_get_model ();
+                gtk_tree_model_get_iter (model, &iter, path);
+
+                gtk_tree_store_set (
+                        GTK_TREE_STORE (model), &iter,
+                        GVA_GAME_STORE_COLUMN_LAST_PLAYED, &now, -1);
+
+                gtk_tree_path_free (path);
+        }
+
+        g_free (name);
+}
+
+static void
 record_game_exited (GvaProcess *process,
                     gint status,
                     gchar *inpname)
@@ -72,7 +117,6 @@ record_game_exited (GvaProcess *process,
         if (process->error == NULL)
                 gva_play_back_show (inpname);
 
-        g_object_unref (process);
         g_free (inpname);
 }
 
@@ -286,6 +330,9 @@ action_play_back_cb (GtkAction *action)
                 gva_wnck_listen_for_new_window (process, name);
                 g_signal_connect_after (
                         process, "exited",
+                        G_CALLBACK (log_lastplayed), g_strdup (name));
+                g_signal_connect_after (
+                        process, "exited",
                         G_CALLBACK (g_object_unref), NULL);
         }
 
@@ -413,8 +460,16 @@ action_record_cb (GtkAction *action)
                 gva_wnck_listen_for_new_window (process, name);
                 g_signal_connect_after (
                         process, "exited",
-                        G_CALLBACK (record_game_exited), inpname);
+                        G_CALLBACK (log_lastplayed), g_strdup (name));
+                g_signal_connect_after (
+                        process, "exited",
+                        G_CALLBACK (record_game_exited), g_strdup (inpname));
+                g_signal_connect_after (
+                        process, "exited",
+                        G_CALLBACK (g_object_unref), NULL);
         }
+
+        g_free (inpname);
 }
 
 /**
@@ -580,6 +635,9 @@ action_start_cb (GtkAction *action)
                 gva_wnck_listen_for_new_window (process, name);
                 g_signal_connect_after (
                         process, "exited",
+                        G_CALLBACK (log_lastplayed), g_strdup (name));
+                g_signal_connect_after (
+                        process, "exited",
                         G_CALLBACK (g_object_unref), NULL);
         }
 }



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