mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
add more columns, and update each time game is saved
This commit is contained in:
parent
7437a71aa6
commit
dddb135b9d
7 changed files with 163 additions and 50 deletions
|
@ -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';
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue