give list adapters a common superclass and move expand/contract logic

there.  To do: moving of group-moving logic.
This commit is contained in:
Eric House 2014-07-02 06:28:15 -07:00
parent 812d533d10
commit 653a1082d9
3 changed files with 362 additions and 154 deletions

View file

@ -141,52 +141,47 @@ public class DictsDelegate extends ListDelegateBase
private boolean m_launchedForMissing = false;
private class DictListAdapter extends XWListAdapter {
private class DictListAdapter extends XWExpListAdapter {
private Context m_context;
private Object[] m_listInfo;
public DictListAdapter( Context context )
{
super( 0 );
super( LangInfo.class );
m_context = context;
}
@Override
public int getCount()
public Object[] makeListData()
{
if ( null == m_listInfo ) {
ArrayList<Object> alist = new ArrayList<Object>();
int nLangs = m_langs.length;
for ( int ii = 0; ii < nLangs; ++ii ) {
String langName = m_langs[ii];
if ( null != m_filterLang &&
! m_filterLang.equals(langName) ) {
continue;
}
ArrayList<Object> items = makeLangItems( langName );
alist.add( new LangInfo( ii, items.size() ) );
if ( ! m_closedLangs.contains( langName ) ) {
alist.addAll( items );
}
ArrayList<Object> alist = new ArrayList<Object>();
int nLangs = m_langs.length;
for ( int ii = 0; ii < nLangs; ++ii ) {
String langName = m_langs[ii];
if ( null != m_filterLang &&
! m_filterLang.equals(langName) ) {
continue;
}
ArrayList<Object> items = makeLangItems( langName );
alist.add( new LangInfo( ii, items.size() ) );
if ( ! m_closedLangs.contains( langName ) ) {
alist.addAll( items );
}
m_listInfo = alist.toArray( new Object[alist.size()] );
}
return m_listInfo.length;
} // getCount
return alist.toArray( new Object[alist.size()] );
} // makeListData
@Override
public int getViewTypeCount() { return 2; }
@Override
public View getView( final int position, View convertView, ViewGroup parent )
public View getView( Object dataObj )
{
View result = null;
Object obj = m_listInfo[position];
if ( obj instanceof LangInfo ) {
LangInfo info = (LangInfo)obj;
if ( dataObj instanceof LangInfo ) {
LangInfo info = (LangInfo)dataObj;
int groupPos = info.m_posn;
String langName = m_langs[groupPos];
int langCode = DictLangCache.getLangLangCode( m_context,
@ -196,8 +191,8 @@ public class DictsDelegate extends ListDelegateBase
info.m_numDicts );
result = ListGroup.make( m_context, DictsDelegate.this,
groupPos, name, expanded );
} else if ( obj instanceof DictAndLoc ) {
DictAndLoc dal = (DictAndLoc)obj;
} else if ( dataObj instanceof DictAndLoc ) {
DictAndLoc dal = (DictAndLoc)dataObj;
XWListItem item =
XWListItem.inflate( m_activity, DictsDelegate.this );
result = item;
@ -216,8 +211,8 @@ public class DictsDelegate extends ListDelegateBase
m_selDicts.put( name, item );
item.setSelected( true );
}
} else if ( obj instanceof DictInfo ) {
DictInfo info = (DictInfo)obj;
} else if ( dataObj instanceof DictInfo ) {
DictInfo info = (DictInfo)dataObj;
XWListItem item =
XWListItem.inflate( m_activity, DictsDelegate.this );
result = item;
@ -240,29 +235,26 @@ public class DictsDelegate extends ListDelegateBase
return result;
}
private XWExpListAdapter.ItemTest makeTestFor( final String langName )
{
return new XWExpListAdapter.ItemTest() {
public boolean isItem( Object item ) {
LangInfo info = (LangInfo)item;
return m_langs[info.m_posn].equals( langName );
}
};
}
protected void removeLangItems( String langName )
{
ArrayList<Object> asList = new ArrayList<Object>();
asList.addAll( Arrays.asList( m_listInfo ) );
int indx = findLangItem( langName ) + 1;
while ( indx < asList.size() && ! (asList.get(indx) instanceof LangInfo) ) {
asList.remove( indx );
}
m_listInfo = asList.toArray( new Object[asList.size()] );
int indx = findGroupItem( makeTestFor( langName ) );
removeChildrenOf( indx );
}
protected void addLangItems( String langName )
{
ArrayList<Object> asList = new ArrayList<Object>();
asList.addAll( Arrays.asList( m_listInfo ) );
ArrayList<Object> items = makeLangItems( langName );
int indx = findLangItem( langName );
asList.addAll( 1 + indx, items );
m_listInfo = asList.toArray( new Object[asList.size()] );
int indx = findGroupItem( makeTestFor( langName ) );
addChildrenOf( indx, makeLangItems( langName ) );
}
private ArrayList<Object> makeLangItems( String langName )
@ -298,24 +290,6 @@ public class DictsDelegate extends ListDelegateBase
return result;
}
private int findLangItem( String langName )
{
int result = -1;
int nLangs = m_langs.length;
for ( int ii = 0; ii < m_listInfo.length; ++ii ) {
Object obj = m_listInfo[ii];
if ( obj instanceof LangInfo ) {
if ( m_langs[((LangInfo)obj).m_posn].equals( langName ) ) {
result = ii;
break;
}
}
}
Assert.assertTrue( -1 != result );
DbgUtils.logf( "findLangItem(%s) => %d", langName, result );
return result;
}
}
protected DictsDelegate( ListActivity activity, Bundle savedInstanceState )
@ -685,8 +659,6 @@ public class DictsDelegate extends ListDelegateBase
m_adapter.removeLangItems( langName );
}
saveClosed();
// mkListAdapter();
m_adapter.notifyDataSetChanged();
}
//////////////////////////////////////////////////////////////////////

View file

@ -45,6 +45,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -73,21 +74,16 @@ public class GamesListDelegate extends ListDelegateBase
private static final String REMATCH_ROWID_EXTRA = "rowid_rm";
private static final String ALERT_MSG = "alert_msg";
private class GameListAdapter2 extends XWListAdapter {
private int m_nGroups = 0;
private Object[] m_listObjs = null;
private class GameListAdapter extends XWExpListAdapter {
private int m_fieldID;
private Map<Long,GameGroupInfo> m_gameInfo;
private long[] m_groupPositions;
private class GroupRec {
public GroupRec( long groupID, int position, GameGroupInfo ggi )
public GroupRec( long groupID, int position )
{
m_ggi = ggi;
m_groupID = groupID;
m_position = position;
}
GameGroupInfo m_ggi;
long m_groupID;
int m_position;
}
@ -99,55 +95,45 @@ public class GamesListDelegate extends ListDelegateBase
long m_rowID;
}
GameListAdapter2()
GameListAdapter()
{
super();
m_gameInfo = DBUtils.getGroups( m_activity );
super( GroupRec.class );
m_groupPositions = checkPositions();
}
@Override
public int getCount()
protected Object[] makeListData()
{
if ( null == m_listObjs ) {
m_nGroups = 0;
ArrayList<Object> alist = new ArrayList<Object>();
long[] positions = getGroupPositions();
for ( int ii = 0; ii < positions.length; ++ii ) {
long groupID = positions[ii];
GameGroupInfo ggi = m_gameInfo.get( groupID );
int nKids = ggi.m_count;
alist.add( new GroupRec( groupID, ii, ggi ) );
++m_nGroups;
DbgUtils.logf( "GamesListDelegate.makeListData()" );
final Map<Long,GameGroupInfo> gameInfo = DBUtils.getGroups( m_activity );
ArrayList<Object> alist = new ArrayList<Object>();
long[] positions = getGroupPositions();
for ( int ii = 0; ii < positions.length; ++ii ) {
long groupID = positions[ii];
GameGroupInfo ggi = gameInfo.get( groupID );
int nKids = ggi.m_count;
// m_groupIndices[ii] = alist.size();
alist.add( new GroupRec( groupID, ii ) );
// DbgUtils.logf( "getCount(): m_expanded[%d] = %b", groupPosition,
// ggi.m_expanded );
if ( ggi.m_expanded ) {
long[] rows = DBUtils.getGroupGames( m_activity, groupID );
for ( long row : rows ) {
GameRec rec = new GameRec(row);
alist.add( rec );
}
}
DbgUtils.logf( "makeListData(): m_expanded[%d] = %b", ii, ggi.m_expanded );
if ( ggi.m_expanded ) {
alist.addAll( makeChildren( groupID ) );
}
m_listObjs = alist.toArray( new Object[alist.size()] );
DbgUtils.logf( "new adapter: getCount() => %d", m_listObjs.length );
}
return m_listObjs.length;
return alist.toArray( new Object[alist.size()] );
}
@Override
public int getViewTypeCount() { return 2; }
@Override
public View getView( final int position, View convertView, ViewGroup parent )
public View getView( Object dataObj )
{
View result = null;
Object obj = m_listObjs[position];
if ( obj instanceof GroupRec ) {
GroupRec rec = (GroupRec)obj;
GameGroupInfo ggi = rec.m_ggi;
if ( dataObj instanceof GroupRec ) {
GroupRec rec = (GroupRec)dataObj;
GameGroupInfo ggi = DBUtils.getGroups( m_activity )
.get( rec.m_groupID );
GameListGroup group =
GameListGroup.makeForPosition( m_activity, rec.m_position,
rec.m_groupID, ggi.m_count,
@ -160,13 +146,12 @@ public class GamesListDelegate extends ListDelegateBase
}
String name = LocUtils.getString( m_activity, R.string.group_name_fmt,
groupNames()[rec.m_position],
ggi.m_count );
ggi.m_name, ggi.m_count );
group.setText( name );
group.setSelected( getSelected( group ) );
result = group;
} else if ( obj instanceof GameRec ) {
GameRec rec = (GameRec)obj;
} else if ( dataObj instanceof GameRec ) {
GameRec rec = (GameRec)dataObj;
GameListItem item =
GameListItem.makeForRow( m_activity, rec.m_rowID, m_handler,
m_fieldID, GamesListDelegate.this );
@ -196,8 +181,9 @@ public class GamesListDelegate extends ListDelegateBase
String groupName( long groupID )
{
GameGroupInfo ggi = m_gameInfo.get(groupID);
return ggi.m_name;
final Map<Long,GameGroupInfo> gameInfo =
DBUtils.getGroups( m_activity );
return gameInfo.get(groupID).m_name;
}
long getGroupIDFor( int groupPos )
@ -208,10 +194,12 @@ public class GamesListDelegate extends ListDelegateBase
String[] groupNames()
{
long[] positions = getGroupPositions();
Assert.assertTrue( positions.length == m_gameInfo.size() );
String[] names = new String[m_gameInfo.size()];
final Map<Long,GameGroupInfo> gameInfo =
DBUtils.getGroups( m_activity );
Assert.assertTrue( positions.length == gameInfo.size() );
String[] names = new String[positions.length];
for ( int ii = 0; ii < positions.length; ++ii ) {
names[ii] = m_gameInfo.get( positions[ii] ).m_name;
names[ii] = gameInfo.get( positions[ii] ).m_name;
}
return names;
}
@ -232,9 +220,12 @@ public class GamesListDelegate extends ListDelegateBase
long[] getGroupPositions()
{
final Set<Long> keys = m_gameInfo.keySet(); // do not modify!!!!
// do not modify!!!!
final Set<Long> keys = DBUtils.getGroups( m_activity ).keySet();
if ( null == m_groupPositions ||
m_groupPositions.length != keys.size() ) {
HashSet<Long> unused = new HashSet<Long>( keys );
long[] newArray = new long[unused.size()];
@ -256,36 +247,62 @@ public class GamesListDelegate extends ListDelegateBase
}
m_groupPositions = newArray;
}
String asStr = "";
for ( long id : m_groupPositions ) {
asStr += id + " ";
}
return m_groupPositions;
}
int getGroupCount()
{
return m_nGroups;
}
int getChildrenCount( long groupID )
{
GameGroupInfo ggi = m_gameInfo.get( groupID );
GameGroupInfo ggi = DBUtils.getGroups( m_activity ).get( groupID );
return ggi.m_count;
}
boolean moveGroup( long groupID, int moveBy )
void moveGroup( long groupID, boolean moveUp )
{
int src = getGroupPosition( groupID );
int dest = src + moveBy;
long[] positions = getGroupPositions();
boolean success = 0 <= dest && dest < positions.length;
if ( success ) {
long tmp = positions[src];
positions[src] = positions[dest];
positions[dest] = tmp;
}
return success;
Assert.fail();
// int src = getGroupPosition( groupID );
// int high, low; // high: high index, but lower position on screen
// if ( moveUp ) {
// high = src;
// low = src - 1;
// } else {
// low = src;
// high = src + 1;
// }
// Assert.assertTrue( high > low );
// long[] positions = getGroupPositions();
// boolean success = 0 <= low && high < positions.length;
// if ( success ) {
// long tmp = positions[low];
// positions[low] = positions[high];
// positions[high] = tmp;
// // Now rearrange the array backing the list view so we
// // don't have to create a new adapter.
// int lowIndex = indexForPosition( low );
// GameGroupInfo ggi = ((GroupRec)m_listObjs[lowIndex]).m_ggi;
// int lowLen = 1 + (ggi.m_expanded ? ggi.m_count : 0);
// int highIndex = indexForPosition( high );
// ggi = ((GroupRec)m_listObjs[highIndex]).m_ggi;
// int highLen = 1 + (ggi.m_expanded ? ggi.m_count : 0);
// ArrayList<Object> asList = new ArrayList<Object>();
// asList.addAll( Arrays.asList( m_listObjs ) );
// // get high first since low will change high's indices
// ArrayList<Object> highList = removeRange( asList, highIndex, highLen );
// ArrayList<Object> lowList = removeRange( asList, lowIndex, lowLen );
// DbgUtils.logf( "inserting %s at %d",
// ((GroupRec)highList.iterator().next()).m_ggi.m_name,
// lowIndex );
// asList.addAll( lowIndex, highList );
// DbgUtils.logf( "inserting %s at %d",
// ((GroupRec)lowList.iterator().next()).m_ggi.m_name,
// highIndex + (highLen - lowLen) );
// asList.addAll( highIndex + (highLen - lowLen), lowList );
// Assert.assertTrue( asList.size() == m_listObjs.length );
// m_listObjs = asList.toArray( new Object[asList.size()] );
// }
// return success;
}
boolean setField( String newField )
@ -293,7 +310,7 @@ public class GamesListDelegate extends ListDelegateBase
boolean changed = false;
int newID = fieldToID( newField );
if ( -1 == newID ) {
DbgUtils.logf( "GameListAdapter2.setField(): unable to match"
DbgUtils.logf( "GameListAdapter.setField(): unable to match"
+ " fieldName %s", newField );
} else if ( m_fieldID != newID ) {
m_fieldID = newID;
@ -322,6 +339,63 @@ public class GamesListDelegate extends ListDelegateBase
}
}
void setExpanded( long groupID, boolean expanded )
{
if ( expanded ) {
addChildrenOf( groupID );
} else {
removeChildrenOf( groupID );
}
}
private void removeChildrenOf( long groupID )
{
int indx = findGroupItem( makeTestFor( groupID ) );
GroupRec rec = (GroupRec)getObjectAt( indx );
// rec.m_ggi.m_expanded = false;
removeChildrenOf( indx );
}
private void addChildrenOf( long groupID )
{
int indx = findGroupItem( makeTestFor( groupID ) );
GroupRec rec = (GroupRec)getObjectAt( indx );
// rec.m_ggi.m_expanded = false;
addChildrenOf( indx, makeChildren( groupID ) );
}
private List<Object> makeChildren( long groupID )
{
List<Object> alist = new ArrayList<Object>();
long[] rows = DBUtils.getGroupGames( m_activity, groupID );
for ( long row : rows ) {
alist.add( new GameRec( row ) );
}
DbgUtils.logf( "makeChildren(%d) => %d kids", groupID, alist.size() );
return alist;
}
private XWExpListAdapter.ItemTest makeTestFor( final long groupID )
{
return new XWExpListAdapter.ItemTest() {
public boolean isItem( Object item ) {
GroupRec rec = (GroupRec)item;
return rec.m_groupID == groupID;
}
};
}
private ArrayList<Object> removeRange( ArrayList<Object> list,
int start, int len )
{
DbgUtils.logf( "removeRange(start=%d, len=%d)", start, len );
ArrayList<Object> result = new ArrayList<Object>(len);
for ( int ii = 0; ii < len; ++ii ) {
result.add( list.remove( start ) );
}
return result;
}
private Set<GameListGroup> getGroupsFromElems( Set<Long> selRows )
{
Set<GameListGroup> result = new HashSet<GameListGroup>();
@ -388,8 +462,11 @@ public class GamesListDelegate extends ListDelegateBase
private long[] checkPositions()
{
long[] result = XWPrefs.getGroupPositions( m_activity );
if ( null != result ) {
Set<Long> posns = m_gameInfo.keySet();
final Map<Long,GameGroupInfo> gameInfo =
DBUtils.getGroups( m_activity );
Set<Long> posns = gameInfo.keySet();
if ( result.length != posns.size() ) {
result = null;
} else {
@ -403,7 +480,7 @@ public class GamesListDelegate extends ListDelegateBase
}
return result;
}
}
} // class GameListAdapter
private static final int[] DEBUG_ITEMS = {
// R.id.games_menu_loaddb,
@ -431,7 +508,7 @@ public class GamesListDelegate extends ListDelegateBase
private static boolean s_firstShown = false;
private GamesListActivity m_activity;
private GameListAdapter2 m_adapter;
private GameListAdapter m_adapter;
private Handler m_handler;
private String m_missingDict;
private String m_missingDictName;
@ -760,13 +837,15 @@ public class GamesListDelegate extends ListDelegateBase
}
}
private void moveGroup( long groupID, int moveBy )
private void moveGroup( long groupID, boolean moveUp )
{
if ( m_adapter.moveGroup( groupID, moveBy ) ) {
long[] positions = m_adapter.getGroupPositions();
XWPrefs.setGroupPositions( m_activity, positions );
mkListAdapter();
}
m_adapter.moveGroup( groupID, moveUp );
// long[] positions = m_adapter.getGroupPositions();
// XWPrefs.setGroupPositions( m_activity, positions );
// m_adapter.notifyDataSetChanged();
// // mkListAdapter();
// }
}
protected void onWindowFocusChanged( boolean hasFocus )
@ -1054,7 +1133,9 @@ public class GamesListDelegate extends ListDelegateBase
}
final long[] selRowIDs = getSelRowIDs();
if ( 1 == selRowIDs.length && R.id.games_game_delete != itemID
if ( 1 == selRowIDs.length
&& R.id.games_game_delete != itemID
&& R.id.games_game_move != itemID
&& !checkWarnNoDict( selRowIDs[0], itemID ) ) {
return true; // FIXME: RETURN FROM MIDDLE!!!
}
@ -1213,10 +1294,10 @@ public class GamesListDelegate extends ListDelegateBase
showDialog( DlgID.RENAME_GROUP );
break;
case R.id.games_group_moveup:
moveGroup( groupID, -1 );
moveGroup( groupID, true );
break;
case R.id.games_group_movedown:
moveGroup( groupID, 1 );
moveGroup( groupID, false );
break;
default:
@ -1263,7 +1344,8 @@ public class GamesListDelegate extends ListDelegateBase
DbgUtils.logf( "onGroupExpandedChanged(pos=%d, expanded=%b); groupID = %d",
groupPosition, expanded , groupID );
DBUtils.setGroupExpanded( m_activity, groupID, expanded );
mkListAdapter();
m_adapter.setExpanded( groupID, expanded );
}
private void setTitleBar()
@ -1710,7 +1792,7 @@ public class GamesListDelegate extends ListDelegateBase
private void mkListAdapter()
{
m_adapter = new GameListAdapter2();
m_adapter = new GameListAdapter();
setListAdapterKeepScroll( m_adapter );
// ListView listview = getListView();

View file

@ -0,0 +1,154 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009-2014 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 java.util.Iterator;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import junit.framework.Assert;
abstract class XWExpListAdapter extends XWListAdapter {
interface ItemTest {
boolean isItem( Object item );
}
private Object[] m_listObjs;
private Class m_groupClass;
private int m_nGroups;
public XWExpListAdapter( Class parentClass )
{
m_groupClass = parentClass;
}
abstract Object[] makeListData();
abstract View getView( Object dataObj );
@Override
public int getCount()
{
if ( null == m_listObjs ) {
m_listObjs = makeListData();
m_nGroups = 0;
for ( int ii = 0; ii < m_listObjs.length; ++ii ) {
if ( m_listObjs[ii].getClass() == m_groupClass ) {
++m_nGroups;
}
}
}
return m_listObjs.length;
}
@Override
public View getView( int position, View convertView, ViewGroup parent )
{
if ( null != convertView ) {
DbgUtils.logf( "getView: missing opportunity to reuse view %H",
convertView );
}
View result = getView( m_listObjs[position] );
DbgUtils.logf( "getView(position=%d) => %H (%s)", position, result,
result.getClass().getName() );
return result;
}
protected int getGroupCount()
{
return m_nGroups;
}
protected Object getObjectAt( int indx )
{
return m_listObjs[indx];
}
protected int findGroupItem( ItemTest test )
{
int result = -1;
for ( int ii = 0; ii < m_listObjs.length; ++ii ) {
Object obj = m_listObjs[ii];
if ( obj.getClass() == m_groupClass && test.isItem( obj ) ) {
result = ii;
break;
}
}
return result;
}
protected int indexForPosition( final int posn )
{
int result = -1;
int curGroup = 0;
for ( int ii = 0; ii < m_listObjs.length; ++ii ) {
Object obj = m_listObjs[ii];
if ( obj.getClass() == m_groupClass ) {
if ( curGroup == posn ) {
result = ii;
break;
}
++curGroup;
}
}
DbgUtils.logf( "indexForPosition(%d) => %d", posn, result );
return result;
}
protected void removeChildrenOf( int groupIndex )
{
Assert.assertTrue( m_groupClass == m_listObjs[groupIndex].getClass() );
int end = 1 + groupIndex;
while ( end < m_listObjs.length && ! (m_listObjs[end].getClass() == m_groupClass) ) {
++end;
}
int nChildren = end - groupIndex - 1; // 1: don't remove parent
Object[] newArray = new Object[m_listObjs.length - nChildren];
System.arraycopy( m_listObjs, 0, newArray, 0, groupIndex + 1 ); // 1: include parent
int nAbove = m_listObjs.length - (groupIndex + nChildren + 1);
if ( end < m_listObjs.length ) {
System.arraycopy( m_listObjs, end, newArray, groupIndex + 1,
m_listObjs.length - end );
}
m_listObjs = newArray;
notifyDataSetChanged();
}
protected void addChildrenOf( int groupIndex, List<Object> children )
{
int nToAdd = children.size();
Object[] newArray = new Object[m_listObjs.length + nToAdd];
System.arraycopy( m_listObjs, 0, newArray, 0, groupIndex + 1 ); // up to and including parent
Iterator<Object> iter = children.iterator();
for ( int ii = 0; iter.hasNext(); ++ii ) {
newArray[groupIndex + 1 + ii] = iter.next();
}
System.arraycopy( m_listObjs, groupIndex + 1,
newArray, groupIndex + 1 + nToAdd,
m_listObjs.length - groupIndex - 1 );
m_listObjs = newArray;
notifyDataSetChanged();
}
}