add more columns, and update each time game is saved

This commit is contained in:
Eric House 2013-01-09 06:30:52 -08:00
parent 7437a71aa6
commit dddb135b9d
7 changed files with 163 additions and 50 deletions

View file

@ -1,4 +1,4 @@
/* -*-mode: compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2000-2013 by Eric House (xwords@eehouse.org). All rights
* reserved.
@ -21,6 +21,10 @@
#include "gamesdb.h"
#include "main.h"
static void getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf,
int len );
sqlite3*
openGamesDB( const char* dbName )
{
@ -32,6 +36,10 @@ openGamesDB( const char* dbName )
"CREATE TABLE games ( "
"game BLOB"
",room VARCHAR(32)"
",ended INT(1)"
",turn INT(2)"
",nmoves INT"
",nmissing INT(2)"
")";
result = sqlite3_exec( pDb, createStr, NULL, NULL, NULL );
@ -95,9 +103,39 @@ writeToDB( XWStreamCtxt* stream, void* closure )
sqlite3_finalize( stmt );
}
if ( newGame ) {
(*cGlobals->firstSave)( cGlobals->firstSaveClosure );
(*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame );
}
void
summarize( CommonGlobals* cGlobals )
{
XP_S16 nMoves = model_getNMoves( cGlobals->game.model );
XP_Bool gameOver = server_getGameIsOver( cGlobals->game.server );
XP_S16 turn = server_getCurrentTurn( cGlobals->game.server );
XP_S16 nMissing = 0;
CommsAddrRec addr = {0};
gchar* room = "";
if ( !!cGlobals->game.comms ) {
nMissing = server_getMissingPlayers( cGlobals->game.server );
comms_getAddr( cGlobals->game.comms, &addr );
if ( COMMS_CONN_RELAY == addr.conType ) {
room = addr.u.ip_relay.invite;
}
}
const char* fmt = "UPDATE games SET room='%s', ended=%d, turn=%d, nmissing=%d, nmoves=%d"
" where rowid=%lld";
XP_UCHAR buf[256];
snprintf( buf, sizeof(buf), fmt, room, gameOver?1:0, turn, nMissing, nMoves,
cGlobals->selRow );
XP_LOGF( "query: %s", buf );
sqlite3_stmt* stmt = NULL;
int result = sqlite3_prepare_v2( cGlobals->pDb, buf, -1, &stmt, NULL );
XP_ASSERT( SQLITE_OK == result );
result = sqlite3_step( stmt );
XP_ASSERT( SQLITE_DONE == result );
sqlite3_finalize( stmt );
}
GSList*
@ -132,12 +170,30 @@ listGames( GTKGamesGlobals* gg )
return list;
}
void
getGameName( GTKGamesGlobals* XP_UNUSED(gg), const sqlite3_int64* rowid,
XP_UCHAR* buf, XP_U16 len )
XP_Bool
getGameInfo( GTKGamesGlobals* gg, sqlite3_int64 rowid, GameInfo* gib )
{
snprintf( buf, len, "Game %lld", *rowid );
LOG_RETURNF( "%s", buf );
XP_Bool success = XP_FALSE;
const char* fmt = "SELECT room, ended, turn, nmoves, nmissing "
"FROM games WHERE rowid = %lld";
XP_UCHAR query[256];
snprintf( query, sizeof(query), fmt, rowid );
sqlite3_stmt* ppStmt;
int result = sqlite3_prepare_v2( gg->pDb, query, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result );
result = sqlite3_step( ppStmt );
if ( SQLITE_ROW == result ) {
success = XP_TRUE;
getColumnText( ppStmt, 0, gib->room, sizeof(gib->room) );
gib->gameOver = 1 == sqlite3_column_int( ppStmt, 1 );
gib->turn = sqlite3_column_int( ppStmt, 2 );
gib->nMoves = sqlite3_column_int( ppStmt, 3 );
gib->nMissing = sqlite3_column_int( ppStmt, 4 );
snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid );
}
sqlite3_finalize( ppStmt );
return success;
}
XP_Bool
@ -157,3 +213,13 @@ loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
sqlite3_finalize( ppStmt );
return XP_TRUE;
}
static void
getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf, int len )
{
const unsigned char* txt = sqlite3_column_text( ppStmt, iCol );
int needLen = sqlite3_column_bytes( ppStmt, iCol );
XP_ASSERT( needLen < len );
XP_MEMCPY( buf, txt, needLen );
buf[needLen] = '\0';
}

View file

@ -27,15 +27,25 @@
#include "main.h"
#include "comtypes.h"
typedef struct _GameInfo {
XP_UCHAR name[128];
XP_UCHAR room[128];
XP_S16 nMoves;
XP_Bool gameOver;
XP_S16 turn;
XP_S16 nMissing;
} GameInfo;
sqlite3* openGamesDB( const char* dbName );
void closeGamesDB( sqlite3* dbp );
void writeToDB( XWStreamCtxt* stream, void* closure );
void summarize( CommonGlobals* cGlobals );
/* Return GSList whose data is (ptrs to) rowids */
GSList* listGames( GTKGamesGlobals* gg );
void getGameName( GTKGamesGlobals* gg, const sqlite3_int64* rowid,
XP_UCHAR* buf, XP_U16 len );
XP_Bool getGameInfo( GTKGamesGlobals* gg, sqlite3_int64 rowid, GameInfo* gib );
XP_Bool loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid );
#endif

View file

@ -2393,8 +2393,8 @@ initGlobals( GtkAppGlobals* globals, LaunchParams* params )
globals->cGlobals.socketChanged = gtk_socket_changed;
globals->cGlobals.socketChangedClosure = globals;
globals->cGlobals.firstSave = newGameSaved;
globals->cGlobals.firstSaveClosure = globals;
globals->cGlobals.onSave = onGameSaved;
globals->cGlobals.onSaveClosure = globals;
globals->cGlobals.addAcceptor = gtk_socket_acceptor;
#endif

View file

@ -20,11 +20,15 @@
#ifdef PLATFORM_GTK
#include "xptypes.h"
#include "main.h"
#include "gamesdb.h"
#include "gtkboard.h"
#include "linuxmain.h"
static void onNewData( GTKGamesGlobals* gg, sqlite3_int64 rowid,
XP_Bool isNew );
static void
recordOpened( GTKGamesGlobals* gg, GtkAppGlobals* globals )
{
@ -50,7 +54,8 @@ gameIsOpen( GTKGamesGlobals* gg, sqlite3_int64 rowid )
return found;
}
enum { CHECK_ITEM, ROW_ITEM, NAME_ITEM, N_ITEMS };
enum { CHECK_ITEM, ROW_ITEM, NAME_ITEM, ROOM_ITEM, OVER_ITEM, TURN_ITEM, NMOVES_ITEM, MISSING_ITEM,
N_ITEMS };
static void
tree_selection_changed_cb( GtkTreeSelection* selection, gpointer data )
@ -65,6 +70,16 @@ tree_selection_changed_cb( GtkTreeSelection* selection, gpointer data )
}
}
static void
addTextColumn( GtkWidget* list, const gchar* title, int item )
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column =
gtk_tree_view_column_new_with_attributes( title, renderer, "text",
item, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
}
static GtkWidget*
init_games_list( GTKGamesGlobals* gg )
{
@ -73,26 +88,24 @@ init_games_list( GTKGamesGlobals* gg )
GtkTreeViewColumn* column;
renderer = gtk_cell_renderer_toggle_new();
/* gtk_cell_renderer_toggle_set_activatable( GTK_CELL_RENDERER_TOGGLE(renderer), */
/* TRUE ); */
column =
gtk_tree_view_column_new_with_attributes( "<sel>", renderer, "active",
CHECK_ITEM, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
renderer = gtk_cell_renderer_text_new();
column =
gtk_tree_view_column_new_with_attributes( "Row", renderer, "text",
ROW_ITEM, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
addTextColumn( list, "Row", ROW_ITEM );
addTextColumn( list, "Name", NAME_ITEM );
addTextColumn( list, "Room", ROOM_ITEM );
addTextColumn( list, "Ended", OVER_ITEM );
addTextColumn( list, "Turn", TURN_ITEM );
addTextColumn( list, "NMoves", NMOVES_ITEM );
addTextColumn( list, "NMissing", MISSING_ITEM );
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes( "Name", renderer, "text",
NAME_ITEM, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
GtkListStore* store = gtk_list_store_new( N_ITEMS, G_TYPE_BOOLEAN, G_TYPE_INT64,
G_TYPE_STRING );
GtkListStore* store = gtk_list_store_new( N_ITEMS, G_TYPE_BOOLEAN,
G_TYPE_INT64, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_BOOLEAN,
G_TYPE_INT, G_TYPE_INT,
G_TYPE_INT );
gtk_tree_view_set_model( GTK_TREE_VIEW(list), GTK_TREE_MODEL(store) );
g_object_unref( store );
@ -105,18 +118,34 @@ init_games_list( GTKGamesGlobals* gg )
}
static void
add_to_list( GtkWidget* list, sqlite3_int64* rowid, const gchar* str )
add_to_list( GtkWidget* list, sqlite3_int64 rowid, XP_Bool isNew,
const GameInfo* gib )
{
GtkListStore* store =
GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
GtkListStore* store = GTK_LIST_STORE( model );
GtkTreeIter iter;
gtk_list_store_append( store, &iter );
/* XP_LOGF( "adding %lld, %s", *rowid, str ); */
/* gchar buf[16]; */
/* snprintf( buf, sizeof(buf), "%lld", *rowid ); */
if ( isNew ) {
gtk_list_store_append( store, &iter );
} else {
gboolean valid;
for ( valid = gtk_tree_model_get_iter_first( model, &iter );
valid;
valid = gtk_tree_model_iter_next( model, &iter ) ) {
sqlite3_int64 tmpid;
gtk_tree_model_get( model, &iter, ROW_ITEM, &tmpid, -1 );
if ( tmpid == rowid ) {
break;
}
}
}
gtk_list_store_set( store, &iter,
ROW_ITEM, *rowid,
NAME_ITEM, str,
ROW_ITEM, rowid,
NAME_ITEM, gib->name,
ROOM_ITEM, gib->room,
OVER_ITEM, gib->gameOver,
TURN_ITEM, gib->turn,
NMOVES_ITEM, gib->nMoves,
MISSING_ITEM, gib->nMissing,
-1 );
XP_LOGF( "DONE adding" );
}
@ -207,10 +236,8 @@ makeGamesWindow( GTKGamesGlobals* gg )
GSList* games = listGames( gg );
for ( GSList* iter = games; !!iter; iter = iter->next ) {
XP_UCHAR name[128];
sqlite3_int64* rowid = (sqlite3_int64*)iter->data;
getGameName( gg, rowid, name, VSIZE(name) );
add_to_list( list, rowid, name );
onNewData( gg, *rowid, XP_TRUE );
}
g_slist_free( games );
@ -244,15 +271,22 @@ windowDestroyed( GtkAppGlobals* globals )
(void)g_idle_add( freeGameGlobals, globals );
}
static void
onNewData( GTKGamesGlobals* gg, sqlite3_int64 rowid, XP_Bool isNew )
{
GameInfo gib;
if ( getGameInfo( gg, rowid, &gib ) ) {
add_to_list( gg->listWidget, rowid, isNew, &gib );
}
}
void
newGameSaved( void* closure )
onGameSaved( void* closure, sqlite3_int64 rowid,
XP_Bool firstTime )
{
GtkAppGlobals* globals = (GtkAppGlobals*)closure;
GTKGamesGlobals* gg = globals->gg;
CommonGlobals* cGlobals = &globals->cGlobals;
XP_UCHAR buf[128];
getGameName( gg, &cGlobals->selRow, buf, sizeof(buf) );
add_to_list( gg->listWidget, &cGlobals->selRow, buf );
onNewData( gg, rowid, firstTime );
}
int
@ -261,7 +295,6 @@ gtkmain( LaunchParams* params )
GTKGamesGlobals gg = {0};
gg.selRow = -1;
gg.params = params;
XP_LOGF( "%s: I'M HERE!!! (calling makeGamesDB())", __func__ );
gg.pDb = openGamesDB( params->dbName );
(void)makeGamesWindow( &gg );
@ -269,7 +302,6 @@ gtkmain( LaunchParams* params )
closeGamesDB( gg.pDb );
XP_LOGF( "%s: I'M BACK!!!", __func__ );
return 0;
} /* gtkmain */

View file

@ -25,6 +25,6 @@
int gtkmain( LaunchParams* params );
void windowDestroyed( GtkAppGlobals* globals );
void newGameSaved( void* closure );
void onGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime );
#endif

View file

@ -307,6 +307,10 @@ saveGame( CommonGlobals* cGlobals )
game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
XP_LOGF( "%s: saved", __func__ );
if ( !!cGlobals->pDb ) {
summarize( cGlobals );
}
} else {
XP_LOGF( "%s: simulating save failure", __func__ );
}

View file

@ -163,7 +163,8 @@ typedef struct _TimerInfo {
#endif
} TimerInfo;
typedef void (*FirstSaveFunc)(void* closure);
typedef void (*OnSaveFunc)( void* closure, sqlite3_int64 rowid,
XP_Bool firstTime );
struct CommonGlobals {
LaunchParams* params;
@ -183,8 +184,8 @@ struct CommonGlobals {
SocketChangedFunc socketChanged;
void* socketChangedClosure;
FirstSaveFunc firstSave;
void* firstSaveClosure;
OnSaveFunc onSave;
void* onSaveClosure;
CommsRelayState state;