Merge branch 'android_branch' into send_in_background

This commit is contained in:
eehouse@eehouse.org 2011-09-14 06:47:12 -07:00 committed by Andy2
commit 98c2617613
24 changed files with 1826 additions and 608 deletions

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="26"
android:versionCode="27"
android:versionName="@string/app_version"
>
@ -124,6 +124,18 @@
<service android:name="RelayService"/>
<receiver android:name=".MountEventReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_EJECT" />
<data android:scheme="file" />
</intent-filter>
</receiver>
<!-- <receiver android:name="NBSReceiver"> -->
<!-- <intent-filter android:priority="10"> -->
<!-- <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> -->

View file

@ -1196,6 +1196,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1getState
setBool( env, jgsi, "canHint", info.canHint );
setBool( env, jgsi, "canRedo", info.canRedo);
setBool( env, jgsi, "inTrade", info.inTrade );
setBool( env, jgsi, "tradeTilesSelected", info.tradeTilesSelected );
setBool( env, jgsi, "gameIsConnected", info.gameIsConnected );
setBool( env, jgsi, "canShuffle", info.canShuffle );

View file

@ -6,39 +6,26 @@
</head>
<body>
<b>Crosswords 4.4 beta 33 release</b>
<b>Crosswords 4.4 beta 34 release</b>
<ul>
<li>Use the term "wordlist" instead of "dictionary" to not imply that
there are definitions provided.</li>
<li>Add color of bonus hints -- the 2L etc. that appear on the board
-- to set of editable colors</li>
<li>Don't ignore user's choice of wordlists. THIS MEANS THAT
IN-PROGRESS GAMES NOT USING ENGLISH WILL BREAK. (But they were broken
anyway: using English when you didn't want them to.)</li>
<li>Change how downloaded wordlists are opened to consume much less
Java memory. Downside: wordlists on external storage are not
available when that storage is mounted on a computer over USB.</li>
<li>Vastly (IMO) improve exchanging tiles: when in exchange mode, draw
board disabled, and replace toolbar with buttons for commiting or
abandoning the exchange</li>
<li>Stop getting confused when there are multiple wordlists with the
same name. They'll all show up, and can be deleted.</li>
<li>In the Wordlists screen, hide wordlists stored on external media
when the media's not available. Notice when it becomes available
and redraw the list.</li>
<li>Don't lose language choice for a game if user downloads a new wordlist</li>
<li>Make a game's language one of several configurable attributes
that can be displayed along with the game</li>
<li>Display relay connection state as being in one of three phases:
configured, connected, and with all players present.</li>
<li>Fix rename of games to work when keyboard opened while dialog
up.</li>
<li>Add icons to games list display so it's easier to tell networked
from standalone. These are placeholders until I can get an artist
to help out. :-)</li>
<li>Fix a family of crashes that occurred when dialogs were up and
memory got low: rare, but annoying.</li>
<li>Change how recent score and bonus value are shown after long-tap
on scoreboard entry or bonus square: use Android's Toast feature
instead of drawing directly on the board</li>
</ul>

View file

@ -57,7 +57,6 @@
<string name="key_notagain_sync">key_notagain_sync</string>
<string name="key_notagain_chat">key_notagain_chat</string>
<string name="key_notagain_relay">key_notagain_relay</string>
<string name="key_notagain_newgame">key_notagain_newgame</string>
<string name="key_notagain_hintprev">key_notagain_hintprev</string>
<string name="key_notagain_hintnext">key_notagain_hintnext</string>
<string name="key_notagain_juggle">key_notagain_juggle</string>
@ -69,7 +68,6 @@
<string name="key_notagain_conndall">key_notagain_conndall</string>
<string name="key_notagain_conndfirst">key_notagain_conndfirst</string>
<string name="key_notagain_conndmid">key_notagain_conndmid</string>
<string name="key_notagain_dicts">key_notagain_dicts</string>
<string name="key_notagain_arrow">key_notagain_arrow</string>
<string name="key_notagain_turnchanged">key_notagain_turnchanged</string>
<string name="key_notagain_newfrom">key_notagain_newfrom</string>
@ -80,7 +78,7 @@
<!-- <string name="default_host">10.0.2.2</string> -->
<string name="dict_url">http://eehouse.org/and_wordlists</string>
<string name="app_version">4.4 beta 33</string>
<string name="app_version">4.4 beta 34</string>
<string name="game_url_pathf">//%1$s/redir.php</string>
<!-- Debugging stuff. No point in localizing it. -->
@ -90,6 +88,7 @@
<string name="redir_host">Invite redirect host</string>
<string name="dict_host">Wordlist download URL</string>
<string name="logging_on">Enable logging</string>
<string name="git_rev_title">Source version id</string>
<string name="relay_port">Relay game port</string>
<string name="proxy_port">Relay device port</string>
<string name="name_dict_fmt">%1$s/%2$s</string>

File diff suppressed because it is too large Load diff

View file

@ -1078,7 +1078,9 @@ public class BoardActivity extends XWActivity
resid = R.string.str_no_peek_robot_tiles;
break;
case UtilCtxt.ERR_NO_EMPTY_TRADE:
resid = R.string.str_no_empty_trade;
// This should not be possible as the button's
// disabled when no tiles selected.
Assert.fail();
break;
case UtilCtxt.ERR_TOO_FEW_TILES_LEFT_TO_TRADE:
resid = R.string.str_too_few_tiles_left_to_trade;
@ -1223,9 +1225,9 @@ public class BoardActivity extends XWActivity
updateToolbar();
if ( m_inTrade != m_gsi.inTrade ) {
m_inTrade = m_gsi.inTrade;
adjustTradeVisibility();
m_view.setInTrade( m_inTrade );
}
adjustTradeVisibility();
}
break;
}
@ -1437,6 +1439,9 @@ public class BoardActivity extends XWActivity
{
m_toolbar.setVisibility( m_inTrade? View.GONE : View.VISIBLE );
m_tradeButtons.setVisibility( m_inTrade? View.VISIBLE : View.GONE );
if ( m_inTrade ) {
m_exchCommmitButton.setEnabled( m_gsi.tradeTilesSelected );
}
}
private void setBackgroundColor()

View file

@ -454,7 +454,7 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
secondsLeft%60 );
fillRectOther( rect, CommonPrefs.COLOR_BACKGRND );
m_fillPaint.setColor( adjustColor(m_playerColors[player]) );
m_fillPaint.setColor( m_playerColors[player] );
Rect shorter = new Rect( rect );
shorter.inset( 0, shorter.height() / 5 );

View file

@ -43,6 +43,9 @@ public class DBUtils {
private static final String ROW_ID = "rowid";
private static final String ROW_ID_FMT = "rowid=%d";
private static long s_cachedRowID = -1;
private static byte[] s_cachedBytes = null;
public static interface DBChangeListener {
public void gameSaved( long rowid );
}
@ -568,6 +571,8 @@ public class DBUtils {
}
db.close();
}
setCached( rowid, null ); // force reread
if ( -1 != rowid ) {
notifyListeners( rowid );
}
@ -578,21 +583,24 @@ public class DBUtils {
{
long rowid = lock.getRowid();
Assert.assertTrue( -1 != rowid );
byte[] result = null;
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
byte[] result = getCached( rowid );
if ( null == result ) {
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
String[] columns = { DBHelper.SNAPSHOT };
String selection = String.format( ROW_ID_FMT, rowid );
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
result = cursor.getBlob( cursor
.getColumnIndex(DBHelper.SNAPSHOT));
String[] columns = { DBHelper.SNAPSHOT };
String selection = String.format( ROW_ID_FMT, rowid );
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
result = cursor.getBlob( cursor
.getColumnIndex(DBHelper.SNAPSHOT));
}
cursor.close();
db.close();
}
cursor.close();
db.close();
setCached( rowid, result );
}
return result;
}
@ -803,4 +811,20 @@ public class DBUtils {
}
}
// Trivial one-item cache. Typically bytes are read three times
// in a row, so this saves two DB accesses per game opened. Could
// use a HashMap, but then lots of half-K byte[] chunks would fail
// to gc. This is good enough.
private static byte[] getCached( long rowid )
{
byte[] result = s_cachedRowID == rowid ? s_cachedBytes : null;
return result;
}
private static void setCached( long rowid, byte[] bytes )
{
s_cachedRowID = rowid;
s_cachedBytes = bytes;
}
}

View file

@ -52,6 +52,15 @@ public class DictUtils {
public static final String INVITED = "invited";
private static DictAndLoc[] s_dictListCache = null;
static {
MountEventReceiver.register( new MountEventReceiver.SDCardNotifiee() {
public void cardMounted( boolean nowMounted )
{
invalDictList();
}
} );
}
public static class DictPairs {
public byte[][] m_bytes;
@ -98,6 +107,13 @@ public class DictUtils {
}
}
public static void invalDictList()
{
s_dictListCache = null;
// Should I have a list of folks who want to know when this
// changes?
}
public static DictAndLoc[] dictList( Context context )
{
if ( null == s_dictListCache ) {
@ -188,7 +204,7 @@ public class DictUtils {
success = copyDict( context, name, from, to );
if ( success ) {
deleteDict( context, name, from );
s_dictListCache = null;
invalDictList();
}
}
return success;
@ -251,7 +267,7 @@ public class DictUtils {
Assert.assertTrue( DictLoc.INTERNAL == loc );
context.deleteFile( name );
}
s_dictListCache = null;
invalDictList();
}
public static void deleteDict( Context context, String name )
@ -405,7 +421,7 @@ public class DictUtils {
fos.write( buf, 0, nRead );
}
fos.close();
s_dictListCache = null;
invalDictList();
success = true;
} catch ( java.io.FileNotFoundException fnf ) {
Utils.logf( "saveDict: FileNotFoundException: %s",

View file

@ -23,13 +23,12 @@ package org.eehouse.android.xw4;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ExpandableListActivity;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.widget.TextView;
import android.widget.AdapterView;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -48,6 +47,7 @@ import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.Toast;
import android.preference.PreferenceManager;
import android.net.Uri;
import java.util.HashMap;
import junit.framework.Assert;
import org.eehouse.android.xw4.DictUtils.DictAndLoc;
@ -57,7 +57,7 @@ import org.eehouse.android.xw4.jni.CommonPrefs;
public class DictsActivity extends ExpandableListActivity
implements View.OnClickListener, XWListItem.DeleteCallback,
SDCardWatcher.SDCardNotifiee, DlgDelegate.DlgClickNotify {
MountEventReceiver.SDCardNotifiee, DlgDelegate.DlgClickNotify {
private static final String DICT_DOLAUNCH = "do_launch";
private static final String DICT_LANG_EXTRA = "use_lang";
@ -69,6 +69,9 @@ public class DictsActivity extends ExpandableListActivity
private static final String MOVEFROMLOC = "movefromloc";
private static final String MOVETOLOC = "movetoloc";
private static HashMap<String,Boolean> s_openStates =
new HashMap<String,Boolean>();
// For new callback alternative
private static final int DELETE_DICT_ACTION = 1;
@ -88,7 +91,6 @@ public class DictsActivity extends ExpandableListActivity
private long m_packedPosition;
private DictUtils.DictLoc m_moveFromLoc;
private DictUtils.DictLoc m_moveToLoc;
private SDCardWatcher m_cardWatcher;
private LayoutInflater m_factory;
@ -207,8 +209,13 @@ public class DictsActivity extends ExpandableListActivity
public boolean isChildSelectable( int groupPosition,
int childPosition ) { return true; }
public boolean isEmpty() { return false; }
public void onGroupCollapsed(int groupPosition){}
public void onGroupExpanded(int groupPosition){}
public void onGroupCollapsed(int groupPosition)
{
s_openStates.put( m_langs[groupPosition], false );
}
public void onGroupExpanded(int groupPosition){
s_openStates.put( m_langs[groupPosition], true );
}
public void registerDataSetObserver( DataSetObserver obs ){}
public void unregisterDataSetObserver( DataSetObserver obs ){}
@ -375,7 +382,8 @@ public class DictsActivity extends ExpandableListActivity
protected void onResume()
{
super.onResume();
m_cardWatcher = new SDCardWatcher( this, this );
MountEventReceiver.register( this );
mkListAdapter();
expandGroups();
}
@ -418,10 +426,9 @@ public class DictsActivity extends ExpandableListActivity
}
@Override
protected void onPause() {
m_cardWatcher.close();
m_cardWatcher = null;
super.onPause();
protected void onStop() {
MountEventReceiver.unregister( this );
super.onStop();
}
public void onClick( View v )
@ -560,14 +567,22 @@ public class DictsActivity extends ExpandableListActivity
}
}
m_delegate.showConfirmThen( msg, DELETE_DICT_ACTION );
m_delegate.showConfirmThen( msg, R.string.button_delete,
DELETE_DICT_ACTION );
}
// SDCardWatcher.SDCardNotifiee interface
public void cardMounted()
// MountEventReceiver.SDCardNotifiee interface
public void cardMounted( boolean nowMounted )
{
mkListAdapter();
expandGroups();
Utils.logf( "DictsActivity.cardMounted(%b)", nowMounted );
// post so other SDCardNotifiee implementations get a chance
// to process first: avoid race conditions
new Handler().post( new Runnable() {
public void run() {
mkListAdapter();
expandGroups();
}
} );
}
// DlgDelegate.DlgClickNotify interface
@ -589,6 +604,7 @@ public class DictsActivity extends ExpandableListActivity
DictUtils.deleteDict( this, dict, loc );
DictLangCache.inval( this, dict, loc, false );
mkListAdapter();
expandGroups();
}
private void askStartDownload( int lang, String name )
@ -623,7 +639,14 @@ public class DictsActivity extends ExpandableListActivity
private void expandGroups()
{
for ( int ii = 0; ii < m_langs.length; ++ii ) {
m_expView.expandGroup( ii );
boolean open = true;
String lang = m_langs[ii];
if ( s_openStates.containsKey( lang ) ) {
open = s_openStates.get( lang );
}
if ( open ) {
m_expView.expandGroup( ii );
}
}
}

View file

@ -54,6 +54,7 @@ public class DlgDelegate {
private static final String CALLBACK = "callback";
private static final String MSGID = "msgid";
private static final String PREFSKEY = "prefskey";
private static final String POSBUTTON = "posbutton";
// Cache a couple of callback implementations that never change:
private DialogInterface.OnClickListener m_cbkOnClickLstnr = null;
@ -64,6 +65,7 @@ public class DlgDelegate {
}
private int m_msgID;
private int m_posButton;
private int m_cbckID = 0; // if this can be set twice I have a
// problem. See asserts below.
private String m_msg;
@ -82,6 +84,7 @@ public class DlgDelegate {
m_msg = bundle.getString( MSG );
m_cbckID = bundle.getInt( CALLBACK );
m_msgID = bundle.getInt( MSGID );
m_posButton = bundle.getInt( POSBUTTON );
m_prefsKey = bundle.getInt( PREFSKEY );
}
}
@ -91,6 +94,7 @@ public class DlgDelegate {
outState.putString( MSG, m_msg );
outState.putInt( CALLBACK, m_cbckID );
outState.putInt( MSGID, m_msgID );
outState.putInt( POSBUTTON, m_posButton );
outState.putInt( PREFSKEY, m_prefsKey );
}
@ -137,6 +141,8 @@ public class DlgDelegate {
ad.setMessage( m_activity.getString(m_msgID) );
break;
case CONFIRM_THEN:
ad.getButton(AlertDialog.BUTTON_POSITIVE).
setText( m_activity.getString( m_posButton ) );
ad.setMessage( m_msg );
break;
}
@ -185,8 +191,14 @@ public class DlgDelegate {
}
public void showConfirmThen( String msg, int callbackID )
{
showConfirmThen( msg, R.string.button_ok, callbackID );
}
public void showConfirmThen( String msg, int posButton, int callbackID )
{
m_msg = msg;
m_posButton = posButton;
Assert.assertTrue( 0 != callbackID );
Assert.assertTrue( 0 == m_cbckID );
m_cbckID = callbackID;

View file

@ -518,7 +518,7 @@ public class GamesList extends XWListActivity
case R.id.gamel_menu_delete_all:
if ( DBUtils.gamesList( this ).length > 0 ) {
showConfirmThen( R.string.confirm_delete_all,
DELETE_ALL_ACTION );
R.string.button_delete, DELETE_ALL_ACTION );
}
handled = true;
break;
@ -561,12 +561,14 @@ public class GamesList extends XWListActivity
m_rowid = DBUtils.gamesList( this )[position];
if ( R.id.list_item_delete == menuID ) {
showConfirmThen( R.string.confirm_delete, DELETE_GAME_ACTION );
showConfirmThen( R.string.confirm_delete, R.string.button_delete,
DELETE_GAME_ACTION );
} else {
if ( checkWarnNoDict( m_rowid ) ) {
switch ( menuID ) {
case R.id.list_item_reset:
showConfirmThen( R.string.confirm_reset, RESET_GAME_ACTION );
showConfirmThen( R.string.confirm_reset,
R.string.button_reset, RESET_GAME_ACTION );
break;
case R.id.list_item_config:
GameUtils.doConfig( this, m_rowid, GameConfig.class );

View file

@ -0,0 +1,77 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.HashSet;
import java.util.Iterator;
public class MountEventReceiver extends BroadcastReceiver {
public interface SDCardNotifiee {
void cardMounted( boolean nowMounted );
}
private static HashSet<SDCardNotifiee> s_procs = new HashSet<SDCardNotifiee>();
@Override
public void onReceive( Context context, Intent intent )
{
Utils.logf( "MountEventReceiver.onReceive(%s)", intent.getAction() );
synchronized( s_procs ) {
do {
if ( s_procs.isEmpty() ) {
break;
}
boolean mounted;
String action = intent.getAction();
if ( action.equals( Intent.ACTION_MEDIA_MOUNTED ) ) {
mounted = true;
} else if ( action.equals( Intent.ACTION_MEDIA_EJECT ) ) {
mounted = false;
} else {
break;
}
Iterator<SDCardNotifiee> iter = s_procs.iterator();
while ( iter.hasNext() ) {
iter.next().cardMounted( mounted );
}
} while ( false );
}
}
public static void register( SDCardNotifiee proc )
{
synchronized( s_procs ) {
s_procs.add( proc );
}
}
public static void unregister( SDCardNotifiee proc )
{
synchronized( s_procs ) {
s_procs.remove( proc );
}
}
}

View file

@ -1,68 +0,0 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class SDCardWatcher {
public interface SDCardNotifiee {
void cardMounted();
}
private UmountReceiver m_rcvr;
private Context m_context;
private SDCardNotifiee m_notifiee;
private class UmountReceiver extends BroadcastReceiver {
@Override
public void onReceive( Context context, Intent intent )
{
if ( intent.getAction().
equals( Intent.ACTION_MEDIA_MOUNTED ) ) {
m_notifiee.cardMounted();
}
}
}
public SDCardWatcher( Context context, SDCardNotifiee notifiee )
{
m_context = context;
m_rcvr = new UmountReceiver();
m_notifiee = notifiee;
IntentFilter filter =
new IntentFilter( Intent.ACTION_MEDIA_MOUNTED );
// filter.addAction( Intent.ACTION_MEDIA_UNMOUNTED );
// filter.addAction( Intent.ACTION_MEDIA_EJECT );
filter.addDataScheme( "file" );
/*Intent intent = */context.getApplicationContext().
registerReceiver( m_rcvr, filter );
}
public void close()
{
m_context.getApplicationContext().unregisterReceiver( m_rcvr );
}
}

View file

@ -84,6 +84,13 @@ public class Utils {
}
} // logf
public static void showf( Context context, String format, Object... args )
{
Formatter formatter = new Formatter();
String msg = formatter.format( format, args ).toString();
Toast.makeText( context, msg, Toast.LENGTH_SHORT ).show();
} // showf
public static void printStack( StackTraceElement[] trace )
{
if ( s_doLog ) {

View file

@ -137,6 +137,11 @@ public class XWListActivity extends ListActivity
showConfirmThen( getString(msg), action );
}
protected void showConfirmThen( int msg, int posButton, int action )
{
m_delegate.showConfirmThen( getString(msg), posButton, action );
}
protected void doSyncMenuitem()
{
m_delegate.doSyncMenuitem();

View file

@ -94,6 +94,7 @@ public class JNIThread extends Thread {
public boolean canHint;
public boolean canRedo;
public boolean inTrade;
public boolean tradeTilesSelected;
public boolean gameIsConnected;
public boolean canShuffle;
public GameStateInfo clone() {

View file

@ -4,18 +4,30 @@ set -u -e
declare -A ENG_IDS
LOCS=""
LIST_ONLY=""
PAIRS_ONLY=""
SEARCH_SOURCE=1
ENG=~/dev/git/ANDROID_BRANCH/xwords4/android/XWords4/res/values/strings.xml
# ENG=~/dev/git/ANDROID_BRANCH/xwords4/android/XWords4/res/values/strings.xml
usage() {
echo "usage: $0 [--loc <path_to_strings.xml>]*" >&2
echo "usage: $0 (--loc <path_to_strings.xml>)+ [--list-only] [--pairs-only]" >&2
exit 1
}
list_ids() {
XML_FILE=$1
xmlstarlet sel -T -t -m "/resources/string" -v @name -o " " $XML_FILE
xmlstarlet sel -T -t -m "/resources/string" -v @name -n $XML_FILE
}
list_pairs() {
XML_FILE=$1
#xmlstarlet sel -t -m "//string" -v @name -o ':' -v . -n $XML_FILE | tr -d '\n' | sed 's, *, ,g'
for NAME in $(list_ids $XML_FILE); do
xmlstarlet sel -t -m "//string[@name='$NAME']" -v @name -o ':' -v . $XML_FILE \
| tr -d '\n' | sed 's, *, ,g'
echo ""
done
}
while [ $# -gt 0 ]; do
@ -26,6 +38,12 @@ while [ $# -gt 0 ]; do
LOCS="$LOCS $2"
shift
;;
--list-only)
LIST_ONLY=1
;;
--pairs-only)
PAIRS_ONLY=1
;;
*)
usage
;;
@ -33,9 +51,27 @@ while [ $# -gt 0 ]; do
shift
done
[ -n "$LOCS" ] || usage
if [ -n "$LIST_ONLY" ]; then
for LOC in $LOCS; do
list_ids $LOC
done
exit 0
fi
if [ -n "$PAIRS_ONLY" ]; then
for LOC in $LOCS; do
list_pairs $LOC
done
exit 0
fi
# echo "checking $ENG for ids not in any .java file"
for ID in $(list_ids $ENG); do
ENG_IDS[$ID]=1
for LOC in $LOCS; do
for ID in $(list_ids $LOC); do
ENG_IDS[$ID]=1
done
done
if [ -n "$SEARCH_SOURCE" ]; then

View file

@ -748,11 +748,7 @@ board_commitTurn( BoardCtxt* board )
if ( board->gameOver || turn < 0 ) {
/* do nothing */
} else if ( turn != board->selPlayer ) {
if ( board->selInfo->tradeInProgress ) {
result = exitTradeMode( board );
} else {
util_userError( board->util, ERR_NOT_YOUR_TURN );
}
util_userError( board->util, ERR_NOT_YOUR_TURN );
} else if ( 0 == model_getNumTilesTotal( board->model, turn ) ) {
/* game's over but still undoable so turn hasn't changed; do
nothing */
@ -761,14 +757,14 @@ board_commitTurn( BoardCtxt* board )
TileBit traySelBits = pti->traySelBits;
result = XP_TRUE; /* there's at least the window to clean up
after */
/* server_commitTrade() changes selPlayer, so board_endTrade
must be called first() */
(void)board_endTrade( board );
if ( NO_TILES == traySelBits ) {
util_userError( board->util, ERR_NO_EMPTY_TRADE );
} else if ( util_userQuery( board->util, QUERY_COMMIT_TRADE,
(XWStreamCtxt*)NULL ) ) {
/* server_commitTrade() changes selPlayer, so board_endTrade
must be called first() */
(void)board_endTrade( board );
(void)server_commitTrade( board->server, traySelBits );
}
} else {
@ -1594,9 +1590,12 @@ board_flip( BoardCtxt* board )
} /* board_flip */
XP_Bool
board_inTrade( const BoardCtxt* board )
board_inTrade( const BoardCtxt* board, XP_Bool* anySelected )
{
const PerTurnInfo* pti = &board->pti[board->selPlayer];
if ( !!anySelected ) {
*anySelected = 0 != pti->traySelBits;
}
return pti->tradeInProgress;
}
@ -2099,7 +2098,7 @@ board_beginTrade( BoardCtxt* board )
XP_Bool
board_endTrade( BoardCtxt* board )
{
XP_Bool result = board_inTrade( board );
XP_Bool result = board_inTrade( board, NULL );
if ( result ) {
PerTurnInfo* pti = board->selInfo;
invalSelTradeWindow( board );

View file

@ -100,7 +100,7 @@ XP_Bool board_draw( BoardCtxt* board );
XP_Bool board_get_flipped( const BoardCtxt* board );
XP_Bool board_flip( BoardCtxt* board );
XP_Bool board_inTrade( const BoardCtxt* board );
XP_Bool board_inTrade( const BoardCtxt* board, XP_Bool* anySelected );
XP_Bool board_get_showValues( const BoardCtxt* board );
XP_Bool board_toggle_showValues( BoardCtxt* board );
XP_Bool board_replaceTiles( BoardCtxt* board );

View file

@ -283,7 +283,7 @@ game_getState( const XWGame* game, GameStateInfo* gsi )
gsi->visTileCount = board_visTileCount( game->board );
gsi->canHint = board_canHint( game->board );
gsi->canRedo = board_canTogglePending( game->board );
gsi->inTrade = board_inTrade( game->board );
gsi->inTrade = board_inTrade( game->board, &gsi->tradeTilesSelected );
gsi->gameIsConnected = !!game->comms && comms_canChat( game->comms );
gsi->canShuffle = board_canShuffle( game->board );
}

View file

@ -93,6 +93,7 @@ typedef struct _GameStateInfo {
XP_Bool canHint;
XP_Bool canRedo;
XP_Bool inTrade;
XP_Bool tradeTilesSelected;
XP_Bool gameIsConnected;
XP_Bool canShuffle;
} GameStateInfo;

View file

@ -2135,6 +2135,8 @@ server_commitTrade( ServerCtxt* server, TileBit selBits )
pool_replaceTiles( server->pool, &oldTiles );
model_makeTileTrade( server->vol.model, server->nv.currentTurn,
&oldTiles, &newTiles );
sortTilesIf( server, turn );
nextTurn( server, PICK_NEXT );
return XP_TRUE;
} /* server_commitTrade */

45
xwords4/scripts/git-cat.sh Executable file
View file

@ -0,0 +1,45 @@
#!/bin/sh
set -u -e
REV=HEAD
BRANCH=""
FILES=""
usage() {
echo "usage: $0 [--branch BRANCH | --rev REV ] path/to/file [path/to/file]*"
exit 0
}
while [ $# -ge 1 ]; do
case $1 in
--branch)
shift
[ $# -gt 1 ] || usage "--branch requires a parameter"
BRANCH=$1
;;
--rev)
shift
[ $# -gt 1 ] || usage "--rev requires a parameter"
REV=$1
;;
--help)
usage
;;
*)
FILES="$FILES $1"
;;
esac
shift
done
[ -n "$FILES" ] || usage
if [ -n "$BRANCH" ]; then
REV=$(git log $BRANCH | grep '^commit' | head -n 1 | awk '{print $2}')
fi
for FILE in $FILES; do
FILE=$(git ls-files --full-name $FILE)
git show $REV:$FILE
done