bunch of changes moving UI from using one dict per game to one per

player: remove dictName from CurGameInfo and GameSummary classes and
from DB; deal with missing dicts (the warning, fetching and replacing)
when opening games and deleting dicts.  Etc.  Trivial testing passes.
This commit is contained in:
Andy2 2011-04-21 18:37:11 -07:00
parent 3970a3ef8a
commit 60922baf72
12 changed files with 197 additions and 108 deletions

View file

@ -199,8 +199,13 @@
last committed turn? (There is no redo option.)</string>
<string name="confirm_delete_dictf">Are you sure you want to
delete %s? It is used by %d games, and you will not be able to
open them without it.</string>
delete %s?</string>
<string name="confirm_deleteonly_dictf">\u0020It is the only %s
dictionary installed. One or more games will be unopenable
without it.</string>
<string name="confirm_deletemore_dictf">\u0020One or more games
are using it (but there is another %s dictionary installed that
can replace it.)</string>
<string name="hints_allowed">Allow hints</string>
<string name="hints_allowed_sum">Enable the hint feature</string>
@ -382,11 +387,11 @@
<string name="subst_dict_title">Substitute dictionary (wordcount)</string>
<string name="button_substdict">Substitute</string>
<string name="no_dictf">Unable to open game because dictionary %s
not found.</string>
<string name="no_dictf">Unable to open game because no %s
dictionary found.</string>
<string name="no_dict_substf">Unable to open game because
dictionary %s not found. You can download a replacement or
substitute another in the same language.</string>
substitute another %s dictionary.</string>
<string name="msg_ask_password">Password for \"%s\":</string>

View file

@ -994,7 +994,6 @@ public class BoardActivity extends XWActivity
byte[] stream = GameUtils.savedGame( this, m_gameLock );
XwJNI.gi_from_stream( m_gi, stream );
Utils.logf( "loadGame: dict name: %s", m_gi.dictName );
String[] dictNames = m_gi.dictNames();
byte[][] dictBytes = GameUtils.openDicts( this, dictNames );
String langName = m_gi.langName();

View file

@ -47,7 +47,6 @@ public class DBHelper extends SQLiteOpenHelper {
// format
public static final String GAMEID = "GAMEID";
public static final String DICTLANG = "DICTLANG";
public static final String DICTNAME = "DICTNAME";
public static final String HASMSGS = "HASMSGS";
public static final String SNAPSHOT = "SNAPSHOT";
public static final String CONTYPE = "CONTYPE";
@ -85,7 +84,6 @@ public class DBHelper extends SQLiteOpenHelper {
+ RELAYID + " TEXT,"
+ SEED + " INTEGER,"
+ DICTLANG + " INTEGER,"
+ DICTNAME + " TEXT,"
+ SMSPHONE + " TEXT,"
+ SCORES + " TEXT,"

View file

@ -93,7 +93,7 @@ public class DBUtils {
DBHelper.CONTYPE, DBHelper.SERVERROLE,
DBHelper.ROOMNAME, DBHelper.RELAYID,
DBHelper.SMSPHONE, DBHelper.SEED,
DBHelper.DICTLANG, DBHelper.DICTNAME,
DBHelper.DICTLANG,
DBHelper.SCORES, DBHelper.HASMSGS,
DBHelper.LASTPLAY_TIME
};
@ -122,9 +122,6 @@ public class DBUtils {
summary.dictLang =
cursor.getInt(cursor.
getColumnIndex(DBHelper.DICTLANG));
summary.dictName =
cursor.getString(cursor.
getColumnIndex(DBHelper.DICTNAME));
summary.modtime =
cursor.getLong(cursor.
getColumnIndex(DBHelper.LASTPLAY_TIME));
@ -212,7 +209,6 @@ public class DBUtils {
values.put( DBHelper.PLAYERS,
summary.summarizePlayers(context) );
values.put( DBHelper.DICTLANG, summary.dictLang );
values.put( DBHelper.DICTNAME, summary.dictName );
values.put( DBHelper.GAME_OVER, summary.gameOver );
if ( null != summary.scores ) {
@ -244,16 +240,16 @@ public class DBUtils {
}
} // saveSummary
public static int countGamesUsing( Context context, String dict )
public static int countGamesUsing( Context context, int lang )
{
int result = 0;
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
String selection = DBHelper.DICTNAME + " LIKE \'"
+ dict + "\'";
String selection = String.format( "%s = %d", DBHelper.DICTLANG,
lang );
// null for columns will return whole rows: bad
String[] columns = { DBHelper.DICTNAME };
String[] columns = { DBHelper.DICTLANG };
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );

View file

@ -30,6 +30,7 @@ import java.util.Arrays;
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.DictInfo;
import org.eehouse.android.xw4.jni.CommonPrefs;
public class DictLangCache {
private static final HashMap<String,DictInfo> s_nameToLang =
@ -157,6 +158,22 @@ public class DictLangCache {
return langs.toArray( result );
}
public static String getBestDefault( Context context, int lang,
boolean human )
{
String dict = human? CommonPrefs.getDefaultHumanDict( context )
: CommonPrefs.getDefaultRobotDict( context );
if ( lang != DictLangCache.getDictLangCode( context, dict ) ) {
String dicts[] = getHaveLang( context, lang );
if ( dicts.length > 0 ) {
dict = dicts[0];
} else {
dict = null;
}
}
return dict;
}
private static String[] getNamesArray( Context context )
{
if ( null == s_langNames ) {

View file

@ -149,20 +149,29 @@ public class DictsActivity extends XWListActivity
public void deleteCalled( final int myPosition )
{
final String dict = m_dicts[myPosition];
int nGames = DBUtils.countGamesUsing( this, dict );
if ( nGames == 0 ) {
deleteDict( dict );
} else {
DialogInterface.OnClickListener action =
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
deleteDict( dict );
}
};
String fmt = getString( R.string.confirm_delete_dictf );
String msg = String.format( fmt, dict, nGames );
showConfirmThen( msg, action );
int lang = DictLangCache.getDictLangCode( this, dict );
int nGames = DBUtils.countGamesUsing( this, lang );
String msg = String.format( getString( R.string.confirm_delete_dictf ),
dict );
DialogInterface.OnClickListener action =
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
deleteDict( dict );
}
};
if ( nGames > 0 ) {
int fmt;
if ( 1 == DictLangCache.getHaveLang( this, lang ).length ) {
fmt = R.string.confirm_deleteonly_dictf;
} else {
fmt = R.string.confirm_deletemore_dictf;
}
String langName = DictLangCache.getLangName( this, lang );
msg += String.format( getString(fmt), langName );
}
showConfirmThen( msg, action );
}
private void deleteDict( String dict )

View file

@ -351,7 +351,8 @@ public class GameConfig extends XWActivity
(Spinner)((Dialog)di).findViewById( R.id.dict_spinner );
int position = spinner.getSelectedItemPosition();
lp.dictName = DictLangCache.getHaveLang( this, m_gi.dictLang )[position];
Utils.logf( "reading name via position %d: %s", position, lp.dictName );
Utils.logf( "reading name for player %d via position %d: %s",
m_whichPlayer, position, lp.dictName );
lp.setIsRobot( Utils.getChecked( dialog, R.id.robot_check ) );
lp.isLocal = !Utils.getChecked( dialog, R.id.remote_check );
@ -423,10 +424,10 @@ public class GameConfig extends XWActivity
handleLockedChange();
}
int curSel = listAvailableLangs( m_giOrig.dictName );
m_giOrig.dictLang =
DictLangCache.getDictLangCode( this,
GameUtils.dictList( this )[curSel] );
int curSel = listAvailableLangs( m_giOrig.dictLang );
// m_giOrig.dictLang =
// DictLangCache.getDictLangCode( this,
// GameUtils.dictList( this )[curSel] );
m_gi = new CurGameInfo( this, m_giOrig );
m_carOrig = new CommsAddrRec( this );
@ -647,15 +648,18 @@ public class GameConfig extends XWActivity
return result;
}
private int listAvailableLangs( String curDict )
private int listAvailableLangs( int langCode )
{
String[] langs =
DictLangCache.listLangs( this, GameUtils.dictList( this ) );
String curLang = DictLangCache.getLangName( this, curDict );
String curLang = DictLangCache.getLangName( this, langCode );
Utils.logf( "listAvailableLangs: %s is current", curLang );
m_langs = buildListWithBrowse( langs );
m_langsBrowsePosition = m_langs.length - 1;
return Arrays.binarySearch( m_langs, curLang );
int index = Arrays.binarySearch( m_langs, curLang );
Utils.logf( "listAvailableLangs: index is %d", index );
return index;
} // listAvailableLangs
private void configDictSpinner( final Dialog dialog, final LocalPlayer lp )
@ -681,8 +685,9 @@ public class GameConfig extends XWActivity
startActivity( Utils.mkDownloadActivity(GameConfig.this,
m_gi.dictLang ) );
} else {
// lp.dictName = dicts[position];
// Utils.logf( "set lp.dictName: %s", lp.dictName );
// why did I disable these two lines?
lp.dictName = dicts[position];
Utils.logf( "set lp.dictName: %s", lp.dictName );
}
}
@ -715,7 +720,7 @@ public class GameConfig extends XWActivity
public void onNothingSelected(AdapterView<?> parentView) {}
};
configSpinnerWDownload( m_langSpinner, m_langs,
listAvailableLangs( m_gi.dictName ),
listAvailableLangs( m_gi.dictLang ),
onSel );
}

View file

@ -29,10 +29,12 @@ import java.io.FileOutputStream;
import java.io.InputStream;
import android.net.Uri;
import java.util.ArrayList;
import java.util.Arrays;
import android.content.res.AssetManager;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
import java.util.HashMap;
import java.util.HashSet;
import junit.framework.Assert;
@ -336,41 +338,48 @@ public class GameUtils {
return lock;
}
public static boolean gameDictHere( Context context, String path )
public static boolean gameDictsHere( Context context, String path )
{
return gameDictHere( context, path, null, null );
return gameDictsHere( context, path, null, null );
}
public static boolean gameDictHere( Context context, String path,
String[] missingName,
int[] missingLang )
// Return true if all dicts present. Return list of those that
// are not.
public static boolean gameDictsHere( Context context, String path,
String[][] missingNames,
int[] missingLang )
{
byte[] stream = savedGame( context, path );
CurGameInfo gi = new CurGameInfo( context );
XwJNI.gi_from_stream( gi, stream );
String dictName = removeDictExtn( gi.dictName );
if ( null != missingName ) {
missingName[0] = dictName;
}
final String[] dictNames = gi.dictNames( false );
HashSet<String> missingSet;
String[] installed = dictList( context );
if ( null != missingLang ) {
missingLang[0] = gi.dictLang;
}
boolean exists = false;
for ( String name : dictList( context ) ) {
if ( name.equals( dictName ) ){
exists = true;
break;
}
missingSet = new HashSet<String>( Arrays.asList( dictNames ) );
Utils.logf( "missingSet before remove of %s: %s", installed.toString(),
missingSet.toString() );
Utils.logf( "missingSet size: %d", missingSet.size() );
missingSet.removeAll( Arrays.asList(installed) );
Utils.logf( "missingSet after remove: %s", missingSet.toString() );
boolean allHere = 0 == missingSet.size();
if ( null != missingNames ) {
missingNames[0] =
missingSet.toArray( new String[missingSet.size()] );
}
return exists;
return allHere;
}
public static boolean gameDictHere( Context context, int indx,
String[] name, int[] lang )
public static boolean gameDictsHere( Context context, int indx,
String[][] name, int[] lang )
{
String path = DBUtils.gamesList( context )[indx];
return gameDictHere( context, path, name, lang );
return gameDictsHere( context, path, name, lang );
}
public static String newName( Context context )
@ -635,27 +644,32 @@ public class GameUtils {
// This *must* involve a reset if the language is changing!!!
// Which isn't possible right now, so make sure the old and new
// dict have the same langauge code.
public static void replaceDict( Context context, String path,
String dict )
public static void replaceDicts( Context context, String game,
String oldDict, String newDict )
{
Assert.fail();
// GameLock lock = new GameLock( path, true ).lock();
// byte[] stream = savedGame( context, lock );
// CurGameInfo gi = new CurGameInfo( context );
// byte[] dictBytes = openDict( context, dict );
GameLock lock = new GameLock( game, true ).lock();
byte[] stream = savedGame( context, lock );
CurGameInfo gi = new CurGameInfo( context );
XwJNI.gi_from_stream( gi, stream );
// int gamePtr = XwJNI.initJNI();
// XwJNI.game_makeFromStream( gamePtr, stream,
// JNIUtilsImpl.get(), gi,
// dictBytes, dict,
// CommonPrefs.get( context ) );
// gi.dictName = dict;
// first time required so dictNames() will work
gi.replaceDicts( newDict );
// saveGame( context, gamePtr, gi, lock, false );
String[] dictNames = gi.dictNames();
byte[][] dictBytes = openDicts( context, dictNames );
int gamePtr = XwJNI.initJNI();
XwJNI.game_makeFromStream( gamePtr, stream, JNIUtilsImpl.get(), gi,
dictBytes, dictNames, gi.langName(),
CommonPrefs.get( context ) );
// second time required as game_makeFromStream can overwrite
gi.replaceDicts( newDict );
// summarizeAndClose( context, lock, gamePtr, gi );
saveGame( context, gamePtr, gi, lock, false );
// lock.unlock();
summarizeAndClose( context, lock, gamePtr, gi );
lock.unlock();
}
public static void applyChanges( Context context, CurGameInfo gi,

View file

@ -59,7 +59,7 @@ public class GamesList extends XWListActivity
private GameListAdapter m_adapter;
private String m_missingDict;
private Handler m_handler;
private String m_missingDictName;
private String[] m_missingDictNames;
private String m_missingDictPath;
private String[] m_sameLangDicts;
private int m_missingDictLang;
@ -88,19 +88,29 @@ public class GamesList extends XWListActivity
case WARN_NODICT_SUBST:
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
Intent intent =
Utils.mkDownloadActivity( GamesList.this,
m_missingDictName,
m_missingDictLang );
startActivity( intent );
for ( String name : m_missingDictNames ) {
Intent intent =
Utils.mkDownloadActivity( GamesList.this,
name,
m_missingDictLang );
startActivity( intent );
}
}
};
int fmtId = WARN_NODICT == id? R.string.no_dictf
: R.string.no_dict_substf;
String message;
String langName = DictLangCache.getLangName( this,
m_missingDictLang );
if ( WARN_NODICT == id ) {
message = String.format( getString(R.string.no_dictf),
langName );
} else {
message = String.format( getString(R.string.no_dict_substf),
m_missingDictNames[0], langName );
}
ab = new AlertDialog.Builder( this )
.setTitle( R.string.no_dict_title )
.setMessage( String.format( getString( fmtId ),
m_missingDictName ) )
.setMessage( message )
.setPositiveButton( R.string.button_ok, null )
.setNegativeButton( R.string.button_download, lstnr )
;
@ -126,9 +136,11 @@ public class GamesList extends XWListActivity
int which ) {
String dict = m_sameLangDicts[which];
dict = DictLangCache.stripCount( dict );
GameUtils.replaceDict( GamesList.this,
m_missingDictPath,
dict );
GameUtils.
replaceDicts( GamesList.this,
m_missingDictPath,
m_missingDictNames[0],
dict );
}
})
;
@ -458,12 +470,13 @@ public class GamesList extends XWListActivity
private boolean checkWarnNoDict( String path )
{
String[] missingName = new String[1];
String[][] missingNames = new String[1][];
int[] missingLang = new int[1];
boolean hasDict = GameUtils.gameDictHere( this, path,
missingName, missingLang );
if ( !hasDict ) {
m_missingDictName = missingName[0];
boolean hasDicts = GameUtils.gameDictsHere( this, path,
missingNames,
missingLang );
if ( !hasDicts ) {
m_missingDictNames = missingNames[0];
m_missingDictLang = missingLang[0];
m_missingDictPath = path;
if ( 0 == DictLangCache.getLangCount( this, m_missingDictLang ) ) {
@ -472,7 +485,7 @@ public class GamesList extends XWListActivity
showDialog( WARN_NODICT_SUBST );
}
}
return hasDict;
return hasDicts;
}
private String saveNew( CurGameInfo gi )
@ -515,7 +528,7 @@ public class GamesList extends XWListActivity
if ( null != relayIDs ) {
for ( String relayID : relayIDs ) {
String path = DBUtils.getPathFor( this, relayID );
if ( GameUtils.gameDictHere( this, path ) ) {
if ( GameUtils.gameDictsHere( this, path ) ) {
GameUtils.launchGame( this, path );
break;
}

View file

@ -87,7 +87,7 @@ public class RelayGameActivity extends XWActivity
}
XwJNI.game_dispose( gamePtr );
String lang = DictLangCache.getLangName( this, m_gi.dictName );
String lang = DictLangCache.getLangName( this, m_gi.dictLang );
String fmt = getString( R.string.relay_game_explainf );
TextView text = (TextView)findViewById( R.id.explain );
text.setText( String.format( fmt, lang ) );

View file

@ -22,6 +22,8 @@ package org.eehouse.android.xw4.jni;
import java.util.Random;
import android.content.Context;
import java.util.HashSet;
import java.util.Arrays;
import junit.framework.Assert;
import org.eehouse.android.xw4.Utils;
@ -36,7 +38,6 @@ public class CurGameInfo {
public enum XWPhoniesChoice { PHONIES_IGNORE, PHONIES_WARN, PHONIES_DISALLOW };
public enum DeviceRole { SERVER_STANDALONE, SERVER_ISSERVER, SERVER_ISCLIENT };
public String dictName;
public LocalPlayer[] players;
public int dictLang;
public int gameID;
@ -74,7 +75,7 @@ public class CurGameInfo {
players = new LocalPlayer[MAX_NUM_PLAYERS];
serverRole = isNetworked ? DeviceRole.SERVER_ISCLIENT
: DeviceRole.SERVER_STANDALONE;
dictName = CommonPrefs.getDefaultHumanDict( context );
String dictName = CommonPrefs.getDefaultHumanDict( context );
dictLang = DictLangCache.getDictLangCode( context, dictName );
hintsNotAllowed = !CommonPrefs.getDefaultHintsAllowed( context );
phoniesAction = CommonPrefs.getDefaultPhonies( context );
@ -106,7 +107,6 @@ public class CurGameInfo {
boardSize = src.boardSize;
players = new LocalPlayer[MAX_NUM_PLAYERS];
serverRole = src.serverRole;
dictName = src.dictName;
dictLang = src.dictLang;
hintsNotAllowed = src.hintsNotAllowed;
phoniesAction = src.phoniesAction;
@ -237,7 +237,14 @@ public class CurGameInfo {
public String[] dictNames()
{
assignDicts();
return dictNames( true );
}
public String[] dictNames( boolean assign )
{
if ( assign ) {
assignDicts();
}
String[] result = new String[nPlayers];
for ( int ii = 0; ii < nPlayers; ++ii ) {
@ -246,6 +253,24 @@ public class CurGameInfo {
return result;
}
// Replace any dict that doesn't exist with newDict
public void replaceDicts( String newDict )
{
String[] dicts =
DictLangCache.getHaveLang( m_context, dictLang );
HashSet<String> installed = new HashSet<String>( Arrays.asList(dicts) );
for ( int ii = 0; ii < nPlayers; ++ii ) {
String curDict = players[ii].dictName;
if ( newDict.equals( curDict ) ) {
// we're good
} else if ( installed.contains(curDict) ) {
// we're good
} else {
players[ii].dictName = newDict;
}
}
}
public String langName()
{
return DictLangCache.getLangName( m_context, dictLang );
@ -325,15 +350,25 @@ public class CurGameInfo {
private void assignDicts()
{
String humanDict = CommonPrefs.getDefaultHumanDict( m_context );
int lang = DictLangCache.getDictLangCode( m_context, humanDict );
Assert.assertTrue( lang == dictLang );
String robotDict = CommonPrefs.getDefaultRobotDict( m_context );
// For each player's dict, if non-null and language matches
// leave it alone. Otherwise replace with default if that
// matches langauge. Otherwise pick an arbitrary dict in the
// right language.
String humanDict =
DictLangCache.getBestDefault( m_context, dictLang, true );
String robotDict =
DictLangCache.getBestDefault( m_context, dictLang, false );
for ( int ii = 0; ii < nPlayers; ++ii ) {
LocalPlayer lp = players[ii];
if ( null == lp.dictName ) {
lp.dictName = lp.isRobot() ? robotDict : humanDict;
} else if ( dictLang !=
DictLangCache.getDictLangCode( m_context,
lp.dictName ) ) {
} else {
continue;
}
lp.dictName = lp.isRobot() ? robotDict : humanDict;
}
}
}

View file

@ -53,7 +53,6 @@ public class GameSummary {
public long modtime;
public int dictLang;
public String dictName;
public CurGameInfo.DeviceRole serverRole;
@ -68,7 +67,6 @@ public class GameSummary {
super();
nPlayers = gi.nPlayers;
dictLang = gi.dictLang;
dictName = gi.dictName;
serverRole = gi.serverRole;
m_gi = gi;
}