Rewrite MotorBrowser to use a fragment for the list. This is the first step in making this portion of the application look and operate better on tables.

This commit is contained in:
Kevin Ruland 2012-01-30 03:48:42 +00:00
parent b5d7143803
commit d8d9f499b7
13 changed files with 719 additions and 202 deletions

View File

@ -71,8 +71,8 @@
<category android:name="android.intent.category.PREFERENCE" />
</intent-filter>
</activity>
<activity android:name=".android.motor.MotorHierarchicalBrowser" />
<activity android:name=".android.motor.MotorDetails" />
<activity android:name=".android.motor.MotorBrowserActivity" />
<activity android:name=".android.motor.MotorDetailsActivity" />
<activity android:name=".android.thrustcurve.TCQueryActivity" />
<activity android:name=".android.simulation.SimulationViewActivity" />
<activity android:name=".android.filebrowser.SimpleFileBrowser" />

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="@+id/motorListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ExpandableListView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No motors" />
</LinearLayout>

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="Download from ThrustCurve" android:id="@+id/download_from_thrustcurve_menu_option"/>
<item android:title="Preferences" android:id="@+id/preference_menu_option"/>
</menu>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/download_from_thrustcurve_menu_option"
android:title="Download from ThrustCurve"/>
<item
android:id="@+id/preference_menu_option"
android:icon="@drawable/ic_menu_preferences"
android:title="@string/Preferences"/>
</menu>

View File

@ -1,6 +1,7 @@
package net.sf.openrocket.android;
import net.sf.openrocket.android.motor.MotorHierarchicalBrowser;
import net.sf.openrocket.android.motor.MotorBrowserActivity;
import net.sf.openrocket.android.thrustcurve.TCQueryActivity;
import android.app.Activity;
import android.content.Intent;
@ -8,14 +9,18 @@ public abstract class ActivityHelpers {
public static void browseMotors( Activity parent ) {
Intent i = new Intent(parent, MotorHierarchicalBrowser.class);
Intent i = new Intent(parent, MotorBrowserActivity.class);
parent.startActivity(i);
}
public static void startPreferences( Activity parent ) {
Intent intent = new Intent(parent, PreferencesActivity.class);
parent.startActivity(intent);
}
public static void downloadFromThrustcurve( Activity parent ) {
Intent i = new Intent(parent, TCQueryActivity.class);
parent.startActivity(i);
}
}

View File

@ -8,7 +8,7 @@ import java.io.ObjectOutputStream;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.util.Coordinate;
abstract class ConversionUtils {
public abstract class ConversionUtils {
static double[] stringToDelays( String value ) {
if (value == null || "".equals(value) ) {
@ -28,7 +28,7 @@ abstract class ConversionUtils {
return values;
}
static String delaysToString( double[] delays ) {
public static String delaysToString( double[] delays ) {
StringBuilder s = new StringBuilder();
boolean first = true;
for( double d:delays ) {

View File

@ -0,0 +1,91 @@
package net.sf.openrocket.android.motor;
import net.sf.openrocket.R;
import net.sf.openrocket.android.ActivityHelpers;
import net.sf.openrocket.android.PreferencesActivity;
import net.sf.openrocket.android.simulation.SimulationChart;
import net.sf.openrocket.android.simulation.SimulationFragment;
import net.sf.openrocket.android.simulation.SimulationViewActivity;
import net.sf.openrocket.android.thrustcurve.TCQueryActivity;
import net.sf.openrocket.android.util.AndroidLogWrapper;
import net.sf.openrocket.document.Simulation;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
public class MotorBrowserActivity extends FragmentActivity
implements MotorListFragment.OnMotorSelectedListener
{
MotorListFragment motorList;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
motorList = MotorListFragment.newInstance();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(android.R.id.content, motorList);
ft.commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.motor_browser_option_menu, menu);
return true;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
AndroidLogWrapper.d(MotorBrowserActivity.class,"onMenuItemSelected" + item.getItemId());
switch(item.getItemId()) {
case R.id.download_from_thrustcurve_menu_option:
ActivityHelpers.downloadFromThrustcurve(this);
return true;
case R.id.preference_menu_option:
Intent intent = new Intent().setClass(this, PreferencesActivity.class);
this.startActivity(intent);
return true;
}
return super.onMenuItemSelected(featureId, item);
}
@Override
public void onMotorSelected(long motorId) {
View sidepane = findViewById(R.id.sidepane);
if ( /* if multi pane */ sidepane != null ) {
/*
Simulation sim = app.getRocketDocument().getSimulation(simulationId);
SimulationChart chart = new SimulationChart(simulationId);
Fragment graph = SimulationFragment.newInstance(chart);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// probably only want to update back stack for first time.
ft.addToBackStack("simulationplot");
ft.replace(R.id.sidepane, graph);
ft.show(graph);
ft.commit();
*/
} else {
Intent i = new Intent(this,MotorDetailsActivity.class);
i.putExtra("Motor", motorId);
startActivity(i);
}
}
}

View File

@ -12,7 +12,7 @@ import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.SlidingDrawer;
public class MotorDetails extends FragmentActivity
public class MotorDetailsActivity extends FragmentActivity
implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener {
private final static String TAG = "MotorDetails";

View File

@ -1,8 +1,7 @@
package net.sf.openrocket.android.motor;
import java.util.Arrays;
import net.sf.openrocket.R;
import net.sf.openrocket.android.db.ConversionUtils;
import net.sf.openrocket.motor.ThrustCurveMotor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@ -39,7 +38,7 @@ public class MotorDetailsFragment extends Fragment {
ThrustCurveMotor tcm = m.getThrustCurveMotor();
manuField.setText( tcm.getManufacturer().getDisplayName());
nameField.setText( tcm.getDesignation() );
delaysField.setText( Arrays.toString(tcm.getStandardDelays()) );
delaysField.setText( ConversionUtils.delaysToString(tcm.getStandardDelays()) );
caseField.setText( m.getCaseInfo());
impulseClassField.setText( m.getImpulseClass());
diameterField.setText( String.valueOf(tcm.getDiameter()*1000.0) );

View File

@ -1,10 +1,12 @@
package net.sf.openrocket.android.motor;
import net.sf.openrocket.R;
import net.sf.openrocket.android.PreferencesActivity;
import net.sf.openrocket.android.db.DbAdapter;
import net.sf.openrocket.android.db.MotorDao;
import net.sf.openrocket.android.thrustcurve.TCQueryActivity;
import net.sf.openrocket.android.util.AndroidLogWrapper;
import net.sf.openrocket.android.util.PersistentExpandableListFragment;
import net.sf.openrocket.motor.Motor;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -12,11 +14,9 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.CursorTreeAdapter;
@ -25,14 +25,23 @@ import android.widget.ResourceCursorTreeAdapter;
import android.widget.TextView;
public class MotorHierarchicalBrowser
extends PersistentExpandableListActivity
/*
* TODO - make this work with PersistentExpandableListFragment.
*
*/
public class MotorListFragment extends PersistentExpandableListFragment
implements SharedPreferences.OnSharedPreferenceChangeListener
{
private static final String TAG = "MotorHierarchicalBrowser";
private static final int ACTIVITY_DOWNLOAD=0;
public interface OnMotorSelectedListener {
public void onMotorSelected( long motorId );
}
public static MotorListFragment newInstance( ) {
MotorListFragment frag = new MotorListFragment();
return frag;
}
private static final int CONTEXTMENU_DELETE = Menu.FIRST+1;
private String groupColumnPreferenceKey;
@ -48,6 +57,13 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
private CursorTreeAdapter mAdapter;
private DbAdapter mDbHelper;
private OnMotorSelectedListener motorSelectedListener;
public void setMotorSelectedListener(
OnMotorSelectedListener motorSelectedListener) {
this.motorSelectedListener = motorSelectedListener;
}
public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter
{
@ -62,12 +78,12 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
@Override
protected Cursor getChildrenCursor(Cursor arg0) {
Log.d(TAG,"getChildrenCursor");
AndroidLogWrapper.d(MotorListFragment.class,"getChildrenCursor");
String group = arg0.getString(arg0.getColumnIndex(groupColumn));
Log.d(TAG," for: "+ groupColumn + " = " + group);
AndroidLogWrapper.d(MotorListFragment.class," for: "+ groupColumn + " = " + group);
Cursor c = mDbHelper.getMotorDao().fetchAllInGroups(groupColumn,group);
Log.d(TAG," got cursor");
startManagingCursor(c);
AndroidLogWrapper.d(MotorListFragment.class," got cursor");
getActivity().startManagingCursor(c);
return c;
}
@ -111,8 +127,6 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
}
}
}
@Override
@ -124,20 +138,8 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbHelper = new DbAdapter(this);
mDbHelper.open();
Resources resources = this.getResources();
groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
setGroupColumnFromPreferences(pref);
pref.registerOnSharedPreferenceChangeListener(this);
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
refreshData();
registerForContextMenu(getExpandableListView());
@ -145,37 +147,29 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.motor_browser_option_menu, menu);
return true;
}
public void onAttach(Activity activity) {
super.onAttach(activity);
mDbHelper = new DbAdapter(getActivity());
mDbHelper.open();
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
Log.d(TAG,"onMenuItemSelected" + item.getItemId());
switch(item.getItemId()) {
case R.id.download_from_thrustcurve_menu_option:
tcDownload();
return true;
case R.id.preference_menu_option:
Intent intent = new Intent().setClass(this, PreferencesActivity.class);
this.startActivity(intent);
return true;
Resources resources = this.getResources();
groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
setGroupColumnFromPreferences(pref);
pref.registerOnSharedPreferenceChangeListener(this);
if ( activity instanceof OnMotorSelectedListener ) {
motorSelectedListener = (OnMotorSelectedListener) activity;
}
return super.onMenuItemSelected(featureId, item);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
Log.d(TAG,"onCreateContextMenu " + menuInfo);
Log.d(TAG, "v.getId() = " + v.getId());
Log.d(TAG, "motorListView = " + R.id.motorListView);
// if (v.getId() == R.id.motorListView) {
ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
menu.setHeaderTitle("context menu");
menu.setHeaderTitle("Motor Operations");
menu.add(Menu.NONE,CONTEXTMENU_DELETE,CONTEXTMENU_DELETE,"Delete");
// }
super.onCreateContextMenu(menu, v, menuInfo);
}
@ -183,7 +177,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
public boolean onContextItemSelected(MenuItem item) {
ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
long motorId = info.id;
Log.d(TAG,"ContextMenu: " + motorId);
AndroidLogWrapper.d(MotorListFragment.class,"ContextMenu: " + motorId);
switch(item.getItemId()) {
case CONTEXTMENU_DELETE:
mDbHelper.getMotorDao().deleteMotor(motorId);
@ -193,28 +187,20 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
return super.onContextItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
refreshData();
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
super.onChildClick(parent, v, groupPosition, childPosition, id);
//Intent i = new Intent(this, BurnPlotActivity.class);
Intent i = new Intent(this,MotorDetails.class);
i.putExtra("Motor", id);
startActivity(i);
if( motorSelectedListener != null ) {
motorSelectedListener.onMotorSelected(id);
}
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
public void onDetach() {
super.onDetach();
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
pref.unregisterOnSharedPreferenceChangeListener(this);
// Null out the group cursor. This will cause the group cursor and all of the child cursors
@ -225,11 +211,6 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
mDbHelper.close();
}
private void tcDownload() {
Intent i = new Intent(this, TCQueryActivity.class);
startActivityForResult(i, ACTIVITY_DOWNLOAD);
}
private void setGroupColumnFromPreferences( SharedPreferences prefs ) {
String indexStr = prefs.getString(groupColumnPreferenceKey, "1");
int index;
@ -250,10 +231,10 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
mAdapter.changeCursor(null);
}
Cursor motorCursor = mDbHelper.getMotorDao().fetchGroups(groupColumn);
startManagingCursor(motorCursor);
getActivity().startManagingCursor(motorCursor);
// Set up our adapter
mAdapter = new MotorHierarchicalListAdapter(
this,
getActivity(),
motorCursor,
R.layout.motor_list_group,
R.layout.motor_list_child);

View File

@ -1,91 +0,0 @@
package net.sf.openrocket.android.motor;
import java.util.ArrayList;
import java.util.List;
import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
public class PersistentExpandableListActivity extends ExpandableListActivity {
private long[] expandedIds;
@Override
protected void onStart() {
super.onStart();
if (this.expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
@Override
protected void onStop() {
super.onStop();
expandedIds = getExpandedIds();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
this.expandedIds = getExpandedIds();
outState.putLongArray("ExpandedIds", this.expandedIds);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
long[] expandedIds = state.getLongArray("ExpandedIds");
if (expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
private long[] getExpandedIds() {
ExpandableListView list = getExpandableListView();
ExpandableListAdapter adapter = getExpandableListAdapter();
if (adapter != null) {
int length = adapter.getGroupCount();
ArrayList<Long> expandedIds = new ArrayList<Long>();
for(int i=0; i < length; i++) {
if(list.isGroupExpanded(i)) {
expandedIds.add(adapter.getGroupId(i));
}
}
return toLongArray(expandedIds);
} else {
return null;
}
}
private void restoreExpandedState(long[] expandedIds) {
this.expandedIds = expandedIds;
if (expandedIds != null) {
ExpandableListView list = getExpandableListView();
ExpandableListAdapter adapter = getExpandableListAdapter();
if (adapter != null) {
for (int i=0; i<adapter.getGroupCount(); i++) {
long id = adapter.getGroupId(i);
if (inArray(expandedIds, id)) list.expandGroup(i);
}
}
}
}
private static boolean inArray(long[] array, long element) {
for (long l : array) {
if (l == element) {
return true;
}
}
return false;
}
private static long[] toLongArray(List<Long> list) {
long[] ret = new long[list.size()];
int i = 0;
for (Long e : list)
ret[i++] = e.longValue();
return ret;
}
}

View File

@ -0,0 +1,55 @@
package net.sf.openrocket.android.util;
import java.text.MessageFormat;
import android.util.Log;
public class AndroidLogWrapper {
private static final boolean logEnabled = true;
public static void d( Class clzz, String msg, Object ... args ) {
if ( logEnabled ) {
String tag = getTagForClass(clzz);
String formatted = MessageFormat.format(msg, args);
Log.d(tag,formatted);
}
}
public static void e( Class clzz, String msg, Object ... args ) {
if ( logEnabled ) {
String tag = getTagForClass(clzz);
String formatted = MessageFormat.format(msg, args);
Log.e(tag,formatted);
}
}
public static void i( Class clzz, String msg, Object ... args ) {
if ( logEnabled ) {
String tag = getTagForClass(clzz);
String formatted = MessageFormat.format(msg, args);
Log.i(tag,formatted);
}
}
public static void v( Class clzz, String msg, Object ... args ) {
if ( logEnabled ) {
String tag = getTagForClass(clzz);
String formatted = MessageFormat.format(msg, args);
Log.v(tag,formatted);
}
}
public static void w( Class clzz, String msg, Object ... args ) {
if ( logEnabled ) {
String tag = getTagForClass(clzz);
String formatted = MessageFormat.format(msg, args);
Log.w(tag,formatted);
}
}
private static String getTagForClass( Class clzz ) {
String s = clzz.getSimpleName();
return s;
}
}

View File

@ -0,0 +1,344 @@
package net.sf.openrocket.android.util;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
*
* Pulled from https://gist.github.com/1316903
*
* This class has originally been taken from
* http://stackoverflow.com/questions/6051050/expandablelistfragment-with-loadermanager-for-compatibility-package
* and then modified by Manfred Moser <manfred@simpligility.com> to get it to work with the v4 r4 compatibility
* library. With inspirations from the library source.
*
* All ASLv2 licensed.
*/
public class ExpandableListFragment extends Fragment
implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener,
ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener
{
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
final private Handler mHandler = new Handler();
final private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView) parent, v, position, id);
}
};
ExpandableListAdapter mAdapter;
ExpandableListView mList;
View mEmptyView;
TextView mStandardEmptyView;
View mListContainer;
boolean mSetEmptyText;
boolean mListShown;
boolean mFinishedStart = false;
public ExpandableListFragment() {
}
/**
* Provide default implementation to return a simple list view. Subclasses
* can override to replace with their own layout. If doing so, the
* returned view hierarchy <em>must</em> have a ListView whose id
* is {@link android.R.id#list android.R.id.list} and can optionally
* have a sibling view id {@link android.R.id#empty android.R.id.empty}
* that is to be shown when the list is empty.
* <p/>
* <p>If you are overriding this method with your own custom content,
* consider including the standard layout {@link android.R.layout#list_content}
* in your layout file, so that you continue to retain all of the standard
* behavior of ListFragment. In particular, this is currently the only
* way to have the built-in indeterminant progress state be shown.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FrameLayout root = new FrameLayout(getActivity());
FrameLayout lframe = new FrameLayout(getActivity());
lframe.setId(INTERNAL_LIST_CONTAINER_ID);
TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
lframe.addView(tv,
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
ExpandableListView lv = new ExpandableListView(getActivity());
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
lv.setOnChildClickListener(this);
lv.setOnGroupExpandListener(this);
lv.setOnGroupCollapseListener(this);
lframe.addView(lv,
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
root.addView(lframe, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
ListView.LayoutParams lp =
new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
root.setLayoutParams(lp);
return root;
}
/**
* Attach to list view once the view hierarchy has been created.
*/
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ensureList();
}
/** Detach from list view. */
@Override
public void onDestroyView() {
mHandler.removeCallbacks(mRequestFocus);
mList = null;
super.onDestroyView();
}
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the
* data associated with the selected item.
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
public void onListItemClick(ListView l, View v, int position, long id) {
}
/** Provide the cursor for the list view. */
public void setListAdapter(ExpandableListAdapter adapter) {
boolean hadAdapter = mAdapter != null;
mAdapter = adapter;
if (mList != null) {
mList.setAdapter((ExpandableListAdapter) null);
mList.setAdapter(adapter);
if (!mListShown && !hadAdapter) {
// The list was hidden, and previously didn't have an
// adapter. It is now time to show it.
setListShown(true, getView().getWindowToken() != null);
}
}
}
/**
* Set the currently selected list item to the specified
* position with the adapter's data
*/
public void setSelection(int position) {
ensureList();
mList.setSelection(position);
}
public long getSelectedPosition() {
ensureList();
return mList.getSelectedPosition();
}
public long getSelectedId() {
ensureList();
return mList.getSelectedId();
}
public ExpandableListView getExpandableListView() {
ensureList();
return mList;
}
/**
* The default content for a ListFragment has a TextView that can
* be shown when the list is empty. If you would like to have it
* shown, call this method to supply the text it should use.
*/
public void setEmptyText(CharSequence text) {
ensureList();
if (mStandardEmptyView == null) {
throw new IllegalStateException("Can't be used with a custom content view");
}
mStandardEmptyView.setText(text);
if (!mSetEmptyText) {
mList.setEmptyView(mStandardEmptyView);
mSetEmptyText = true;
}
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
* <p/>
* <p>Applications do not normally need to use this themselves. The default
* behavior of ListFragment is to start with the list not being shown, only
* showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.
* If the list at that point had not been shown, when it does get shown
* it will be do without the user ever seeing the hidden state.
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
*/
public void setListShown(boolean shown) {
setListShown(shown, true);
}
/**
* Like {@link #setListShown(boolean)}, but no animation is used when
* transitioning from the previous state.
*/
public void setListShownNoAnimation(boolean shown) {
setListShown(shown, false);
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
* @param animate If true, an animation will be used to transition to the
* new state.
*/
private void setListShown(boolean shown, boolean animate) {
ensureList();
if (mListShown == shown) {
return;
}
mListShown = shown;
if (mListContainer != null) {
if (shown) {
if (animate) {
mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));
}
mListContainer.setVisibility(View.VISIBLE);
} else {
if (animate) {
mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));
}
mListContainer.setVisibility(View.GONE);
}
}
}
/** Get the ListAdapter associated with this activity's ListView. */
public ExpandableListAdapter getExpandableListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
View root = getView();
if (root == null) {
throw new IllegalStateException("Content view not yet created");
}
if (root instanceof ExpandableListView) {
mList = (ExpandableListView) root;
} else {
mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID);
if (mStandardEmptyView == null) {
mEmptyView = root.findViewById(android.R.id.empty);
}
mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);
View rawListView = root.findViewById(android.R.id.list);
if (!(rawListView instanceof ExpandableListView)) {
if (rawListView == null) {
throw new RuntimeException("Your content must have a ExpandableListView whose id attribute is " +
"'android.R.id.list'");
}
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' " +
"that is not a ExpandableListView class");
}
mList = (ExpandableListView) rawListView;
if (mEmptyView != null) {
mList.setEmptyView(mEmptyView);
}
}
mListShown = true;
mList.setOnItemClickListener(mOnClickListener);
if (mAdapter != null) {
setListAdapter(mAdapter);
} else {
// We are starting without an adapter, so assume we won't
// have our data right away and start with the progress indicator.
setListShown(false, false);
}
mHandler.post(mRequestFocus);
}
@Override
public void onGroupExpand(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onGroupCollapse(int arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
}
public void onContentChanged() {
View emptyView = getView().findViewById(android.R.id.empty);
mList = (ExpandableListView) getView().findViewById(android.R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ExpandableListView whose id attribute is " + "'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnChildClickListener(this);
mList.setOnGroupExpandListener(this);
mList.setOnGroupCollapseListener(this);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mFinishedStart = true;
}
}

View File

@ -0,0 +1,145 @@
package net.sf.openrocket.android.util;
/*
* TODO - this isn't working.
*/
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
public class PersistentExpandableListFragment extends ExpandableListFragment {
private long[] expandedIds;
@Override
public void onCreate(Bundle savedInstanceState) {
AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onCreate");
super.onCreate(savedInstanceState);
if ( savedInstanceState != null ) {
expandedIds = savedInstanceState.getLongArray("ExpandedIds");
}
}
@Override
public void onStop() {
AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStop");
super.onStop();
expandedIds = getExpandedIds();
}
@Override
public void onStart() {
AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStart");
super.onStart();
if (this.expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
@Override
public void onPause() {
AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onPause");
super.onPause();
expandedIds = getExpandedIds();
}
@Override
public void onResume() {
AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onResume");
super.onResume();
if (this.expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
this.expandedIds = getExpandedIds();
outState.putLongArray("ExpandedIds", this.expandedIds);
}
/*
@Override
protected void onStart() {
super.onStart();
if (this.expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
@Override
protected void onStop() {
super.onStop();
expandedIds = getExpandedIds();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
this.expandedIds = getExpandedIds();
outState.putLongArray("ExpandedIds", this.expandedIds);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
long[] expandedIds = state.getLongArray("ExpandedIds");
if (expandedIds != null) {
restoreExpandedState(expandedIds);
}
}
*/
private long[] getExpandedIds() {
ExpandableListView list = getExpandableListView();
ExpandableListAdapter adapter = getExpandableListAdapter();
if (adapter != null) {
int length = adapter.getGroupCount();
ArrayList<Long> expandedIds = new ArrayList<Long>();
for(int i=0; i < length; i++) {
if(list.isGroupExpanded(i)) {
expandedIds.add(adapter.getGroupId(i));
}
}
return toLongArray(expandedIds);
} else {
return null;
}
}
private void restoreExpandedState(long[] expandedIds) {
this.expandedIds = expandedIds;
if (expandedIds != null) {
ExpandableListView list = getExpandableListView();
ExpandableListAdapter adapter = getExpandableListAdapter();
if (adapter != null) {
for (int i=0; i<adapter.getGroupCount(); i++) {
long id = adapter.getGroupId(i);
if (inArray(expandedIds, id)) list.expandGroup(i);
}
}
}
}
private static boolean inArray(long[] array, long element) {
for (long l : array) {
if (l == element) {
return true;
}
}
return false;
}
private static long[] toLongArray(List<Long> list) {
long[] ret = new long[list.size()];
int i = 0;
for (Long e : list)
ret[i++] = e.longValue();
return ret;
}
}