Rewrite MotorBrowser to use a fragment for the list. This is the first step in makin...
authorkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 30 Jan 2012 03:48:42 +0000 (03:48 +0000)
committerkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 30 Jan 2012 03:48:42 +0000 (03:48 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@381 180e2498-e6e9-4542-8430-84ac67f01cd8

15 files changed:
android/AndroidManifest.xml
android/res/layout/motor_hierarch_list.xml [deleted file]
android/res/menu/motor_browser_option_menu.xml
android/src/net/sf/openrocket/android/ActivityHelpers.java
android/src/net/sf/openrocket/android/db/ConversionUtils.java
android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/motor/MotorDetails.java [deleted file]
android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java
android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java [deleted file]
android/src/net/sf/openrocket/android/motor/MotorListFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java [deleted file]
android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/util/ExpandableListFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java [new file with mode: 0644]

index de2637f05f7a3ccc9f9cfdda91377f82a5ace970..db3d21f0d574e164eb892d74886609653e6a761a 100644 (file)
@@ -71,8 +71,8 @@
                 <category android:name="android.intent.category.PREFERENCE" />\r
             </intent-filter>\r
         </activity>\r
-        <activity android:name=".android.motor.MotorHierarchicalBrowser" />\r
-        <activity android:name=".android.motor.MotorDetails" />\r
+        <activity android:name=".android.motor.MotorBrowserActivity" />\r
+        <activity android:name=".android.motor.MotorDetailsActivity" />\r
         <activity android:name=".android.thrustcurve.TCQueryActivity" />\r
         <activity android:name=".android.simulation.SimulationViewActivity" />\r
         <activity android:name=".android.filebrowser.SimpleFileBrowser" />\r
diff --git a/android/res/layout/motor_hierarch_list.xml b/android/res/layout/motor_hierarch_list.xml
deleted file mode 100644 (file)
index 9d17a2c..0000000
+++ /dev/null
@@ -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>
\ No newline at end of file
index 5c1f1b44077bcaa47c28e7c2ce7b8b06ddc14811..154bd5955b94e4c4e5412c91546b2548273af9d5 100644 (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>
\ No newline at end of file
index bc6db510b01332351fa562fc696bc8318ef2bb41..aaef2c6fa03c27a9c0d3d47ef4af39a2e03dbcb8 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.android;\r
 \r
-import net.sf.openrocket.android.motor.MotorHierarchicalBrowser;\r
+import net.sf.openrocket.android.motor.MotorBrowserActivity;\r
+import net.sf.openrocket.android.thrustcurve.TCQueryActivity;\r
 import android.app.Activity;\r
 import android.content.Intent;\r
 \r
@@ -8,14 +9,18 @@ public abstract class ActivityHelpers {
 \r
        \r
        public static void browseMotors( Activity parent ) {\r
-               Intent i = new Intent(parent, MotorHierarchicalBrowser.class);\r
+               Intent i = new Intent(parent, MotorBrowserActivity.class);\r
                parent.startActivity(i);\r
-               \r
        }\r
 \r
        public static void startPreferences( Activity parent ) {\r
                Intent intent = new Intent(parent, PreferencesActivity.class);\r
                parent.startActivity(intent);\r
-\r
        }\r
+       \r
+       public static void downloadFromThrustcurve( Activity parent ) {\r
+               Intent i = new Intent(parent, TCQueryActivity.class);\r
+               parent.startActivity(i);\r
+       }\r
+\r
 }\r
index a66fc28cf9e09ca804af2f698206b0519bf4db21..62fbddb9d1f5a58ea3ad7b45c41b55d6a3098cfd 100644 (file)
@@ -8,7 +8,7 @@ import java.io.ObjectOutputStream;
 import net.sf.openrocket.motor.Motor;\r
 import net.sf.openrocket.util.Coordinate;\r
 \r
-abstract class ConversionUtils {\r
+public abstract class ConversionUtils {\r
 \r
        static double[] stringToDelays( String value ) {\r
                if (value == null || "".equals(value) ) {\r
@@ -28,7 +28,7 @@ abstract class ConversionUtils {
                return values;\r
        }\r
        \r
-       static String delaysToString( double[] delays ) {\r
+       public static String delaysToString( double[] delays ) {\r
                StringBuilder s = new StringBuilder();\r
                boolean first = true;\r
                for( double d:delays ) {\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java b/android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java
new file mode 100644 (file)
index 0000000..e059da1
--- /dev/null
@@ -0,0 +1,91 @@
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.ActivityHelpers;\r
+import net.sf.openrocket.android.PreferencesActivity;\r
+import net.sf.openrocket.android.simulation.SimulationChart;\r
+import net.sf.openrocket.android.simulation.SimulationFragment;\r
+import net.sf.openrocket.android.simulation.SimulationViewActivity;\r
+import net.sf.openrocket.android.thrustcurve.TCQueryActivity;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.document.Simulation;\r
+import android.content.Intent;\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.support.v4.app.FragmentActivity;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.view.Menu;\r
+import android.view.MenuInflater;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+\r
+public class MotorBrowserActivity extends FragmentActivity\r
+implements MotorListFragment.OnMotorSelectedListener\r
+{\r
+\r
+       MotorListFragment motorList;\r
+\r
+       /** Called when the activity is first created. */\r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               super.onCreate(savedInstanceState);\r
+\r
+        if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {\r
+               motorList = MotorListFragment.newInstance();\r
+               FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
+               ft.add(android.R.id.content, motorList);\r
+               ft.commit();\r
+        }\r
+       }\r
+\r
+       @Override\r
+       public boolean onCreateOptionsMenu(Menu menu) {\r
+       MenuInflater inflater = getMenuInflater();\r
+       inflater.inflate(R.menu.motor_browser_option_menu, menu);\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+               AndroidLogWrapper.d(MotorBrowserActivity.class,"onMenuItemSelected" + item.getItemId());\r
+               switch(item.getItemId()) {\r
+               case R.id.download_from_thrustcurve_menu_option:\r
+                       ActivityHelpers.downloadFromThrustcurve(this);\r
+                       return true;\r
+               case R.id.preference_menu_option:\r
+                       Intent intent = new Intent().setClass(this, PreferencesActivity.class);\r
+                       this.startActivity(intent);\r
+                       return true;\r
+               }\r
+               return super.onMenuItemSelected(featureId, item);\r
+       }\r
+\r
+       @Override\r
+       public void onMotorSelected(long motorId) {\r
+               \r
+               View sidepane = findViewById(R.id.sidepane);\r
+               if ( /* if multi pane */ sidepane != null ) {\r
+                       /*\r
+                       Simulation sim = app.getRocketDocument().getSimulation(simulationId);\r
+                       SimulationChart chart = new SimulationChart(simulationId);\r
+\r
+                       Fragment graph = SimulationFragment.newInstance(chart);\r
+\r
+                       FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
+                       ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);\r
+                       // probably only want to update back stack for first time.\r
+                       ft.addToBackStack("simulationplot");\r
+                       ft.replace(R.id.sidepane, graph);\r
+                       ft.show(graph);\r
+                       ft.commit();\r
+*/\r
+\r
+               } else {\r
+                       Intent i = new Intent(this,MotorDetailsActivity.class);\r
+                       i.putExtra("Motor", motorId);\r
+                       startActivity(i);\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorDetails.java b/android/src/net/sf/openrocket/android/motor/MotorDetails.java
deleted file mode 100644 (file)
index df31f3b..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-package net.sf.openrocket.android.motor;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.db.DbAdapter;\r
-import android.content.Intent;\r
-import android.os.Bundle;\r
-import android.support.v4.app.FragmentActivity;\r
-import android.util.Log;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
-import android.widget.ImageView;\r
-import android.widget.SlidingDrawer;\r
-\r
-public class MotorDetails extends FragmentActivity\r
-implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener {\r
-\r
-       private final static String TAG = "MotorDetails";\r
-       \r
-       private SlidingDrawer slidingDrawer;\r
-       private ImageView handle;\r
-       \r
-       private ExtendedThrustCurveMotor motor;\r
-       \r
-       @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-               Log.d(TAG,"onCreate Bundle = "+ String.valueOf(savedInstanceState));\r
-               setContentView(R.layout.motor_detail);\r
-\r
-               Intent i = getIntent();\r
-               long motorId = i.getLongExtra("Motor",-1);\r
-\r
-               DbAdapter mDbHelper = new DbAdapter(this);\r
-               mDbHelper.open();\r
-\r
-               try {\r
-                       motor = mDbHelper.getMotorDao().fetchMotor(motorId);\r
-               } catch ( Exception e ) {\r
-                       \r
-               }\r
-\r
-               mDbHelper.close();\r
-               \r
-               BurnPlotFragment burnPlot = (BurnPlotFragment) getSupportFragmentManager().findFragmentById(R.id.burnPlotFragment);\r
-               burnPlot.init(motor);\r
-               \r
-               MotorDetailsFragment motorDetails = (MotorDetailsFragment) getSupportFragmentManager().findFragmentById(R.id.motorDetailForm);\r
-               motorDetails.init(motor);\r
-               \r
-               slidingDrawer = (SlidingDrawer) findViewById(R.id.drawer);\r
-               \r
-               slidingDrawer.setOnDrawerOpenListener(this);\r
-               slidingDrawer.setOnDrawerCloseListener(this);\r
-               \r
-               handle = (ImageView) findViewById(R.id.handle);\r
-               \r
-       }\r
-       \r
-       @Override\r
-       public void onDrawerOpened() {\r
-               handle.setImageResource(R.drawable.arrow_down_float);\r
-       }\r
-       \r
-       @Override\r
-       public void onDrawerClosed() {\r
-               handle.setImageResource(R.drawable.arrow_up_float);\r
-       }\r
-\r
-       @Override\r
-       public boolean onCreateOptionsMenu(Menu menu) {\r
-       MenuInflater inflater = getMenuInflater();\r
-       inflater.inflate(R.menu.motor_details_option_menu, menu);\r
-               return true;\r
-       }\r
-\r
-       @Override\r
-       public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
-               switch(item.getItemId()) {\r
-               case R.id.save:\r
-                       // Extract form data to Motor.\r
-                       // Save motor.\r
-                       return true;\r
-               }\r
-               return super.onMenuItemSelected(featureId, item);\r
-       }\r
-\r
-\r
-}\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java b/android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java
new file mode 100644 (file)
index 0000000..ed97b83
--- /dev/null
@@ -0,0 +1,89 @@
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.DbAdapter;\r
+import android.content.Intent;\r
+import android.os.Bundle;\r
+import android.support.v4.app.FragmentActivity;\r
+import android.util.Log;\r
+import android.view.Menu;\r
+import android.view.MenuInflater;\r
+import android.view.MenuItem;\r
+import android.widget.ImageView;\r
+import android.widget.SlidingDrawer;\r
+\r
+public class MotorDetailsActivity extends FragmentActivity\r
+implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener {\r
+\r
+       private final static String TAG = "MotorDetails";\r
+       \r
+       private SlidingDrawer slidingDrawer;\r
+       private ImageView handle;\r
+       \r
+       private ExtendedThrustCurveMotor motor;\r
+       \r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               super.onCreate(savedInstanceState);\r
+               Log.d(TAG,"onCreate Bundle = "+ String.valueOf(savedInstanceState));\r
+               setContentView(R.layout.motor_detail);\r
+\r
+               Intent i = getIntent();\r
+               long motorId = i.getLongExtra("Motor",-1);\r
+\r
+               DbAdapter mDbHelper = new DbAdapter(this);\r
+               mDbHelper.open();\r
+\r
+               try {\r
+                       motor = mDbHelper.getMotorDao().fetchMotor(motorId);\r
+               } catch ( Exception e ) {\r
+                       \r
+               }\r
+\r
+               mDbHelper.close();\r
+               \r
+               BurnPlotFragment burnPlot = (BurnPlotFragment) getSupportFragmentManager().findFragmentById(R.id.burnPlotFragment);\r
+               burnPlot.init(motor);\r
+               \r
+               MotorDetailsFragment motorDetails = (MotorDetailsFragment) getSupportFragmentManager().findFragmentById(R.id.motorDetailForm);\r
+               motorDetails.init(motor);\r
+               \r
+               slidingDrawer = (SlidingDrawer) findViewById(R.id.drawer);\r
+               \r
+               slidingDrawer.setOnDrawerOpenListener(this);\r
+               slidingDrawer.setOnDrawerCloseListener(this);\r
+               \r
+               handle = (ImageView) findViewById(R.id.handle);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void onDrawerOpened() {\r
+               handle.setImageResource(R.drawable.arrow_down_float);\r
+       }\r
+       \r
+       @Override\r
+       public void onDrawerClosed() {\r
+               handle.setImageResource(R.drawable.arrow_up_float);\r
+       }\r
+\r
+       @Override\r
+       public boolean onCreateOptionsMenu(Menu menu) {\r
+       MenuInflater inflater = getMenuInflater();\r
+       inflater.inflate(R.menu.motor_details_option_menu, menu);\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+               switch(item.getItemId()) {\r
+               case R.id.save:\r
+                       // Extract form data to Motor.\r
+                       // Save motor.\r
+                       return true;\r
+               }\r
+               return super.onMenuItemSelected(featureId, item);\r
+       }\r
+\r
+\r
+}\r
index 874f43439bf2f2518bfff2afb8f1a31d832e5019..f9083b6465048f3813790e8bf20388ccbf4bb0aa 100644 (file)
@@ -1,8 +1,7 @@
 package net.sf.openrocket.android.motor;\r
 \r
-import java.util.Arrays;\r
-\r
 import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.ConversionUtils;\r
 import net.sf.openrocket.motor.ThrustCurveMotor;\r
 import android.os.Bundle;\r
 import android.support.v4.app.Fragment;\r
@@ -39,7 +38,7 @@ public class MotorDetailsFragment extends Fragment {
                ThrustCurveMotor tcm = m.getThrustCurveMotor();\r
                manuField.setText( tcm.getManufacturer().getDisplayName());\r
                nameField.setText( tcm.getDesignation() );\r
-               delaysField.setText( Arrays.toString(tcm.getStandardDelays()) );\r
+               delaysField.setText( ConversionUtils.delaysToString(tcm.getStandardDelays()) );\r
                caseField.setText( m.getCaseInfo());\r
                impulseClassField.setText( m.getImpulseClass());\r
                diameterField.setText( String.valueOf(tcm.getDiameter()*1000.0) );\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java b/android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java
deleted file mode 100644 (file)
index f940e11..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-package net.sf.openrocket.android.motor;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.PreferencesActivity;\r
-import net.sf.openrocket.android.db.DbAdapter;\r
-import net.sf.openrocket.android.db.MotorDao;\r
-import net.sf.openrocket.android.thrustcurve.TCQueryActivity;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.content.res.Resources;\r
-import android.database.Cursor;\r
-import android.os.Bundle;\r
-import android.preference.PreferenceManager;\r
-import android.util.Log;\r
-import android.view.ContextMenu;\r
-import android.view.ContextMenu.ContextMenuInfo;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
-import android.view.View;\r
-import android.widget.CursorTreeAdapter;\r
-import android.widget.ExpandableListView;\r
-import android.widget.ResourceCursorTreeAdapter;\r
-import android.widget.TextView;\r
-\r
-\r
-public class MotorHierarchicalBrowser\r
-extends PersistentExpandableListActivity\r
-implements SharedPreferences.OnSharedPreferenceChangeListener\r
-{\r
-       private static final String TAG = "MotorHierarchicalBrowser";\r
-\r
-       private static final int ACTIVITY_DOWNLOAD=0;\r
-\r
-       private static final int CONTEXTMENU_DELETE = Menu.FIRST+1;\r
-\r
-       private String groupColumnPreferenceKey;\r
-       private String groupColumn = MotorDao.CASE_INFO;\r
-\r
-       private static final String[] groupColumns = new String[] {\r
-               MotorDao.CASE_INFO,\r
-               MotorDao.DIAMETER,\r
-               MotorDao.IMPULSE_CLASS,\r
-               MotorDao.MANUFACTURER\r
-       };\r
-\r
-       private CursorTreeAdapter mAdapter;\r
-\r
-       private DbAdapter mDbHelper;\r
-\r
-       public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter\r
-       {\r
-\r
-               // Note that the constructor does not take a Cursor. This is done to avoid querying the \r
-               // database on the main thread.\r
-               public MotorHierarchicalListAdapter(Context context, Cursor cursor, int groupLayout,\r
-                               int childLayout ) {\r
-\r
-                       super(context, cursor, groupLayout, childLayout);\r
-               }\r
-\r
-               @Override\r
-               protected Cursor getChildrenCursor(Cursor arg0) {\r
-                       Log.d(TAG,"getChildrenCursor");\r
-                       String group = arg0.getString(arg0.getColumnIndex(groupColumn));\r
-                       Log.d(TAG,"  for: "+ groupColumn + " = " + group);\r
-                       Cursor c = mDbHelper.getMotorDao().fetchAllInGroups(groupColumn,group);\r
-                       Log.d(TAG,"  got cursor");\r
-                       startManagingCursor(c);\r
-                       return c;\r
-               }\r
-\r
-               @Override\r
-               public long getGroupId(int groupPosition) {\r
-                       return groupPosition;\r
-               }\r
-\r
-               /* (non-Javadoc)\r
-                * @see android.widget.CursorTreeAdapter#bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
-                */\r
-               @Override\r
-               protected void bindChildView(View arg0, Context arg1, Cursor arg2,\r
-                               boolean arg3) {\r
-                       \r
-                       TextView manu = (TextView) arg0.findViewById(R.id.motorChildManu);\r
-                       manu.setText( arg2.getString(arg2.getColumnIndex(MotorDao.MANUFACTURER)));\r
-                       \r
-                       TextView desig = (TextView) arg0.findViewById(R.id.motorChildName);\r
-                       desig.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DESIGNATION)));\r
-                       \r
-                       TextView delays = (TextView) arg0.findViewById(R.id.motorChildDelays);\r
-                       delays.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DELAYS)));\r
-                       \r
-                       TextView totImpulse = (TextView) arg0.findViewById(R.id.motorChildImpulse);\r
-                       totImpulse.setText( arg2.getString(arg2.getColumnIndex(MotorDao.TOTAL_IMPULSE)));\r
-               }\r
-\r
-               /* (non-Javadoc)\r
-                * @see android.widget.CursorTreeAdapter#bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
-                */\r
-               @Override\r
-               protected void bindGroupView(View view, Context context, Cursor cursor,\r
-                               boolean isExpanded) {\r
-                       TextView v = (TextView) view.findViewById(R.id.motorGroup);\r
-                       if ( MotorDao.DIAMETER.equals(groupColumn)) {\r
-                               double d = cursor.getDouble( cursor.getColumnIndex(groupColumn));\r
-                               v.setText( String.valueOf(Math.round(d * 1000.0)) );\r
-                       } else {\r
-                               v.setText( cursor.getString( cursor.getColumnIndex(groupColumn)));\r
-                       }\r
-               }\r
-               \r
-               \r
-\r
-       }\r
-\r
-       @Override\r
-       public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
-               if ( groupColumnPreferenceKey.equals(arg1) ) {\r
-                       setGroupColumnFromPreferences(arg0);\r
-                       refreshData();\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-\r
-               mDbHelper = new DbAdapter(this);\r
-               mDbHelper.open();\r
-\r
-               Resources resources = this.getResources();\r
-               groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption);\r
-               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
-\r
-               setGroupColumnFromPreferences(pref);\r
-\r
-               pref.registerOnSharedPreferenceChangeListener(this);\r
-\r
-               refreshData();\r
-\r
-               registerForContextMenu(getExpandableListView());\r
-\r
-       }\r
-\r
-       @Override\r
-       public boolean onCreateOptionsMenu(Menu menu) {\r
-       MenuInflater inflater = getMenuInflater();\r
-       inflater.inflate(R.menu.motor_browser_option_menu, menu);\r
-               return true;\r
-       }\r
-\r
-       @Override\r
-       public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
-               Log.d(TAG,"onMenuItemSelected" + item.getItemId());\r
-               switch(item.getItemId()) {\r
-               case R.id.download_from_thrustcurve_menu_option:\r
-                       tcDownload();\r
-                       return true;\r
-               case R.id.preference_menu_option:\r
-                       Intent intent = new Intent().setClass(this, PreferencesActivity.class);\r
-                       this.startActivity(intent);\r
-                       return true;\r
-               }\r
-               return super.onMenuItemSelected(featureId, item);\r
-       }\r
-\r
-       @Override\r
-       public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\r
-               Log.d(TAG,"onCreateContextMenu " + menuInfo);\r
-               Log.d(TAG, "v.getId() = " + v.getId());\r
-               Log.d(TAG, "motorListView = " + R.id.motorListView);\r
-               //      if (v.getId() == R.id.motorListView) {\r
-               ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;\r
-               menu.setHeaderTitle("context menu");\r
-               menu.add(Menu.NONE,CONTEXTMENU_DELETE,CONTEXTMENU_DELETE,"Delete");\r
-               //      }\r
-               super.onCreateContextMenu(menu, v, menuInfo);\r
-       }\r
-\r
-       @Override\r
-       public boolean onContextItemSelected(MenuItem item) {\r
-               ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();\r
-               long motorId = info.id;\r
-               Log.d(TAG,"ContextMenu: " + motorId);\r
-               switch(item.getItemId()) {\r
-               case CONTEXTMENU_DELETE:\r
-                       mDbHelper.getMotorDao().deleteMotor(motorId);\r
-                       refreshData();\r
-                       return true;\r
-               }\r
-               return super.onContextItemSelected(item);\r
-       }\r
-\r
-       @Override\r
-       protected void onActivityResult(int requestCode, int resultCode, Intent intent) {\r
-               super.onActivityResult(requestCode, resultCode, intent);\r
-               refreshData();\r
-       }\r
-\r
-\r
-       @Override\r
-       public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {\r
-               super.onChildClick(parent, v, groupPosition, childPosition, id);\r
-               //Intent i = new Intent(this, BurnPlotActivity.class);\r
-               Intent i = new Intent(this,MotorDetails.class);\r
-               i.putExtra("Motor", id);\r
-               startActivity(i);\r
-               return true;\r
-       }\r
-\r
-       @Override\r
-       protected void onDestroy() {\r
-               super.onDestroy();\r
-               \r
-               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
-               pref.unregisterOnSharedPreferenceChangeListener(this);\r
-\r
-               // Null out the group cursor. This will cause the group cursor and all of the child cursors\r
-               // to be closed.\r
-               mAdapter.changeCursor(null);\r
-               mAdapter = null;\r
-\r
-               mDbHelper.close();\r
-       }\r
-\r
-       private void tcDownload() {\r
-               Intent i = new Intent(this, TCQueryActivity.class);\r
-               startActivityForResult(i, ACTIVITY_DOWNLOAD);\r
-       }\r
-\r
-       private void setGroupColumnFromPreferences( SharedPreferences prefs ) {\r
-               String indexStr = prefs.getString(groupColumnPreferenceKey, "1");\r
-               int index;\r
-               //Dirty hack, you can't use integer-array in ListPreferences\r
-               try {\r
-                       index = Integer.parseInt(indexStr);\r
-               } catch ( Exception e ) {\r
-                       index = 1;\r
-               }\r
-               if ( index >= groupColumns.length ) {\r
-                       index = 1;\r
-               }\r
-               groupColumn = groupColumns[index];\r
-\r
-       }\r
-       private void refreshData() {\r
-               if (mAdapter != null ) {\r
-                       mAdapter.changeCursor(null);\r
-               }\r
-               Cursor motorCursor = mDbHelper.getMotorDao().fetchGroups(groupColumn);\r
-               startManagingCursor(motorCursor);\r
-               // Set up our adapter\r
-               mAdapter = new MotorHierarchicalListAdapter( \r
-                               this,\r
-                               motorCursor,\r
-                               R.layout.motor_list_group,\r
-                               R.layout.motor_list_child);\r
-               setListAdapter(mAdapter);\r
-       }\r
-}\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorListFragment.java b/android/src/net/sf/openrocket/android/motor/MotorListFragment.java
new file mode 100644 (file)
index 0000000..f755985
--- /dev/null
@@ -0,0 +1,243 @@
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.DbAdapter;\r
+import net.sf.openrocket.android.db.MotorDao;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.android.util.PersistentExpandableListFragment;\r
+import net.sf.openrocket.motor.Motor;\r
+import android.app.Activity;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.content.res.Resources;\r
+import android.database.Cursor;\r
+import android.os.Bundle;\r
+import android.preference.PreferenceManager;\r
+import android.view.ContextMenu;\r
+import android.view.ContextMenu.ContextMenuInfo;\r
+import android.view.Menu;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+import android.widget.CursorTreeAdapter;\r
+import android.widget.ExpandableListView;\r
+import android.widget.ResourceCursorTreeAdapter;\r
+import android.widget.TextView;\r
+\r
+\r
+/*\r
+ * TODO - make this work with PersistentExpandableListFragment.\r
+ * \r
+ */\r
+public class MotorListFragment extends PersistentExpandableListFragment\r
+implements SharedPreferences.OnSharedPreferenceChangeListener\r
+{\r
+       public interface OnMotorSelectedListener {\r
+               public void onMotorSelected( long motorId );\r
+       }\r
+       \r
+       public static MotorListFragment newInstance( ) {\r
+               \r
+               MotorListFragment frag = new MotorListFragment();\r
+               return frag;\r
+       }\r
+       \r
+       private static final int CONTEXTMENU_DELETE = Menu.FIRST+1;\r
+\r
+       private String groupColumnPreferenceKey;\r
+       private String groupColumn = MotorDao.CASE_INFO;\r
+\r
+       private static final String[] groupColumns = new String[] {\r
+               MotorDao.CASE_INFO,\r
+               MotorDao.DIAMETER,\r
+               MotorDao.IMPULSE_CLASS,\r
+               MotorDao.MANUFACTURER\r
+       };\r
+\r
+       private CursorTreeAdapter mAdapter;\r
+\r
+       private DbAdapter mDbHelper;\r
+       \r
+       private OnMotorSelectedListener motorSelectedListener;\r
+       \r
+       public void setMotorSelectedListener(\r
+                       OnMotorSelectedListener motorSelectedListener) {\r
+               this.motorSelectedListener = motorSelectedListener;\r
+       }\r
+\r
+       public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter\r
+       {\r
+\r
+               // Note that the constructor does not take a Cursor. This is done to avoid querying the \r
+               // database on the main thread.\r
+               public MotorHierarchicalListAdapter(Context context, Cursor cursor, int groupLayout,\r
+                               int childLayout ) {\r
+\r
+                       super(context, cursor, groupLayout, childLayout);\r
+               }\r
+\r
+               @Override\r
+               protected Cursor getChildrenCursor(Cursor arg0) {\r
+                       AndroidLogWrapper.d(MotorListFragment.class,"getChildrenCursor");\r
+                       String group = arg0.getString(arg0.getColumnIndex(groupColumn));\r
+                       AndroidLogWrapper.d(MotorListFragment.class,"  for: "+ groupColumn + " = " + group);\r
+                       Cursor c = mDbHelper.getMotorDao().fetchAllInGroups(groupColumn,group);\r
+                       AndroidLogWrapper.d(MotorListFragment.class,"  got cursor");\r
+                       getActivity().startManagingCursor(c);\r
+                       return c;\r
+               }\r
+\r
+               @Override\r
+               public long getGroupId(int groupPosition) {\r
+                       return groupPosition;\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see android.widget.CursorTreeAdapter#bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
+                */\r
+               @Override\r
+               protected void bindChildView(View arg0, Context arg1, Cursor arg2,\r
+                               boolean arg3) {\r
+                       \r
+                       TextView manu = (TextView) arg0.findViewById(R.id.motorChildManu);\r
+                       manu.setText( arg2.getString(arg2.getColumnIndex(MotorDao.MANUFACTURER)));\r
+                       \r
+                       TextView desig = (TextView) arg0.findViewById(R.id.motorChildName);\r
+                       desig.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DESIGNATION)));\r
+                       \r
+                       TextView delays = (TextView) arg0.findViewById(R.id.motorChildDelays);\r
+                       delays.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DELAYS)));\r
+                       \r
+                       TextView totImpulse = (TextView) arg0.findViewById(R.id.motorChildImpulse);\r
+                       totImpulse.setText( arg2.getString(arg2.getColumnIndex(MotorDao.TOTAL_IMPULSE)));\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see android.widget.CursorTreeAdapter#bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
+                */\r
+               @Override\r
+               protected void bindGroupView(View view, Context context, Cursor cursor,\r
+                               boolean isExpanded) {\r
+                       TextView v = (TextView) view.findViewById(R.id.motorGroup);\r
+                       if ( MotorDao.DIAMETER.equals(groupColumn)) {\r
+                               double d = cursor.getDouble( cursor.getColumnIndex(groupColumn));\r
+                               v.setText( String.valueOf(Math.round(d * 1000.0)) );\r
+                       } else {\r
+                               v.setText( cursor.getString( cursor.getColumnIndex(groupColumn)));\r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+       @Override\r
+       public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
+               if ( groupColumnPreferenceKey.equals(arg1) ) {\r
+                       setGroupColumnFromPreferences(arg0);\r
+                       refreshData();\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onViewCreated(View view, Bundle savedInstanceState) {\r
+               super.onViewCreated(view, savedInstanceState);\r
+               refreshData();\r
+\r
+               registerForContextMenu(getExpandableListView());\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onAttach(Activity activity) {\r
+               super.onAttach(activity);\r
+               mDbHelper = new DbAdapter(getActivity());\r
+               mDbHelper.open();\r
+\r
+               Resources resources = this.getResources();\r
+               groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption);\r
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
+\r
+               setGroupColumnFromPreferences(pref);\r
+\r
+               pref.registerOnSharedPreferenceChangeListener(this);\r
+               \r
+               if ( activity instanceof OnMotorSelectedListener ) {\r
+                       motorSelectedListener = (OnMotorSelectedListener) activity;\r
+               }\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\r
+               menu.setHeaderTitle("Motor Operations");\r
+               menu.add(Menu.NONE,CONTEXTMENU_DELETE,CONTEXTMENU_DELETE,"Delete");\r
+               super.onCreateContextMenu(menu, v, menuInfo);\r
+       }\r
+\r
+       @Override\r
+       public boolean onContextItemSelected(MenuItem item) {\r
+               ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();\r
+               long motorId = info.id;\r
+               AndroidLogWrapper.d(MotorListFragment.class,"ContextMenu: " + motorId);\r
+               switch(item.getItemId()) {\r
+               case CONTEXTMENU_DELETE:\r
+                       mDbHelper.getMotorDao().deleteMotor(motorId);\r
+                       refreshData();\r
+                       return true;\r
+               }\r
+               return super.onContextItemSelected(item);\r
+       }\r
+\r
+       @Override\r
+       public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {\r
+               super.onChildClick(parent, v, groupPosition, childPosition, id);\r
+               //Intent i = new Intent(this, BurnPlotActivity.class);\r
+               if( motorSelectedListener != null ) {\r
+                       motorSelectedListener.onMotorSelected(id);\r
+               }\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public void onDetach() {\r
+               super.onDetach();\r
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
+               pref.unregisterOnSharedPreferenceChangeListener(this);\r
+\r
+               // Null out the group cursor. This will cause the group cursor and all of the child cursors\r
+               // to be closed.\r
+               mAdapter.changeCursor(null);\r
+               mAdapter = null;\r
+\r
+               mDbHelper.close();\r
+       }\r
+\r
+       private void setGroupColumnFromPreferences( SharedPreferences prefs ) {\r
+               String indexStr = prefs.getString(groupColumnPreferenceKey, "1");\r
+               int index;\r
+               //Dirty hack, you can't use integer-array in ListPreferences\r
+               try {\r
+                       index = Integer.parseInt(indexStr);\r
+               } catch ( Exception e ) {\r
+                       index = 1;\r
+               }\r
+               if ( index >= groupColumns.length ) {\r
+                       index = 1;\r
+               }\r
+               groupColumn = groupColumns[index];\r
+\r
+       }\r
+       private void refreshData() {\r
+               if (mAdapter != null ) {\r
+                       mAdapter.changeCursor(null);\r
+               }\r
+               Cursor motorCursor = mDbHelper.getMotorDao().fetchGroups(groupColumn);\r
+               getActivity().startManagingCursor(motorCursor);\r
+               // Set up our adapter\r
+               mAdapter = new MotorHierarchicalListAdapter( \r
+                               getActivity(),\r
+                               motorCursor,\r
+                               R.layout.motor_list_group,\r
+                               R.layout.motor_list_child);\r
+               setListAdapter(mAdapter);\r
+       }\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java b/android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java
deleted file mode 100644 (file)
index f179374..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-package net.sf.openrocket.android.motor;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import android.app.ExpandableListActivity;\r
-import android.os.Bundle;\r
-import android.widget.ExpandableListAdapter;\r
-import android.widget.ExpandableListView;\r
-\r
-public class PersistentExpandableListActivity extends ExpandableListActivity {\r
-    private long[] expandedIds;\r
-\r
-    @Override\r
-    protected void onStart() {\r
-        super.onStart();\r
-        if (this.expandedIds != null) {\r
-            restoreExpandedState(expandedIds);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected void onStop() {\r
-        super.onStop();\r
-        expandedIds = getExpandedIds();\r
-    }\r
-\r
-    @Override\r
-    protected void onSaveInstanceState(Bundle outState) {\r
-        super.onSaveInstanceState(outState);\r
-        this.expandedIds = getExpandedIds();\r
-        outState.putLongArray("ExpandedIds", this.expandedIds);\r
-    }\r
-\r
-    @Override\r
-    protected void onRestoreInstanceState(Bundle state) {\r
-        super.onRestoreInstanceState(state);\r
-        long[] expandedIds = state.getLongArray("ExpandedIds");\r
-        if (expandedIds != null) {\r
-            restoreExpandedState(expandedIds);\r
-        }\r
-    }\r
-\r
-    private long[] getExpandedIds() {\r
-        ExpandableListView list = getExpandableListView();\r
-        ExpandableListAdapter adapter = getExpandableListAdapter();\r
-        if (adapter != null) {\r
-            int length = adapter.getGroupCount();\r
-            ArrayList<Long> expandedIds = new ArrayList<Long>();\r
-            for(int i=0; i < length; i++) {\r
-                if(list.isGroupExpanded(i)) {\r
-                    expandedIds.add(adapter.getGroupId(i));\r
-                }\r
-            }\r
-            return toLongArray(expandedIds);\r
-        } else {\r
-            return null;\r
-        }\r
-    }\r
-\r
-    private void restoreExpandedState(long[] expandedIds) {\r
-        this.expandedIds = expandedIds;\r
-        if (expandedIds != null) {\r
-            ExpandableListView list = getExpandableListView();\r
-            ExpandableListAdapter adapter = getExpandableListAdapter();\r
-            if (adapter != null) {\r
-                for (int i=0; i<adapter.getGroupCount(); i++) {\r
-                    long id = adapter.getGroupId(i);\r
-                    if (inArray(expandedIds, id)) list.expandGroup(i);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private static boolean inArray(long[] array, long element) {\r
-        for (long l : array) {\r
-            if (l == element) {\r
-                return true;\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-\r
-    private static long[] toLongArray(List<Long> list)  {\r
-        long[] ret = new long[list.size()];\r
-        int i = 0;\r
-        for (Long e : list)  \r
-            ret[i++] = e.longValue();\r
-        return ret;\r
-    }\r
-}\r
diff --git a/android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java b/android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java
new file mode 100644 (file)
index 0000000..456136a
--- /dev/null
@@ -0,0 +1,55 @@
+package net.sf.openrocket.android.util;\r
+\r
+import java.text.MessageFormat;\r
+\r
+import android.util.Log;\r
+\r
+public class AndroidLogWrapper {\r
+\r
+       private static final boolean logEnabled = true;\r
+       \r
+       public static void d( Class clzz, String msg, Object ... args ) {\r
+               \r
+               if ( logEnabled ) {\r
+                       String tag = getTagForClass(clzz);\r
+                       String formatted = MessageFormat.format(msg, args);\r
+                       Log.d(tag,formatted);\r
+               }\r
+       }\r
+\r
+       public static void e( Class clzz, String msg, Object ... args ) {\r
+               if ( logEnabled ) {\r
+                       String tag = getTagForClass(clzz);\r
+                       String formatted = MessageFormat.format(msg, args);\r
+                       Log.e(tag,formatted);\r
+               }\r
+       }\r
+\r
+       public static void i( Class clzz, String msg, Object ... args ) {\r
+               if ( logEnabled ) {\r
+                       String tag = getTagForClass(clzz);\r
+                       String formatted = MessageFormat.format(msg, args);\r
+                       Log.i(tag,formatted);\r
+               }\r
+       }\r
+       public static void v( Class clzz, String msg, Object ... args ) {\r
+               if ( logEnabled ) {\r
+                       String tag = getTagForClass(clzz);\r
+                       String formatted = MessageFormat.format(msg, args);\r
+                       Log.v(tag,formatted);\r
+               }\r
+       }\r
+       public static void w( Class clzz, String msg, Object ... args ) {\r
+               if ( logEnabled ) {\r
+                       String tag = getTagForClass(clzz);\r
+                       String formatted = MessageFormat.format(msg, args);\r
+                       Log.w(tag,formatted);\r
+               }\r
+       }\r
+       \r
+       private static String getTagForClass( Class clzz ) {\r
+               String s = clzz.getSimpleName();\r
+               return s;\r
+       }\r
+       \r
+}\r
diff --git a/android/src/net/sf/openrocket/android/util/ExpandableListFragment.java b/android/src/net/sf/openrocket/android/util/ExpandableListFragment.java
new file mode 100644 (file)
index 0000000..47fc7fe
--- /dev/null
@@ -0,0 +1,344 @@
+package net.sf.openrocket.android.util;\r
+\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.support.v4.app.Fragment;\r
+import android.view.ContextMenu;\r
+import android.view.ContextMenu.ContextMenuInfo;\r
+import android.view.Gravity;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnCreateContextMenuListener;\r
+import android.view.ViewGroup;\r
+import android.view.animation.AnimationUtils;\r
+import android.widget.AdapterView;\r
+import android.widget.ExpandableListAdapter;\r
+import android.widget.ExpandableListView;\r
+import android.widget.FrameLayout;\r
+import android.widget.ListAdapter;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+\r
+/**\r
+ * \r
+ * Pulled from https://gist.github.com/1316903\r
+ * \r
+ * This class has originally been taken from\r
+ * http://stackoverflow.com/questions/6051050/expandablelistfragment-with-loadermanager-for-compatibility-package\r
+ * and then modified by Manfred Moser <manfred@simpligility.com> to get it to work with the v4 r4 compatibility\r
+ * library. With inspirations from the library source.\r
+ *\r
+ * All ASLv2 licensed.\r
+ */\r
+public class ExpandableListFragment extends Fragment\r
+implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener,\r
+ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener\r
+{\r
+\r
+       static final int INTERNAL_EMPTY_ID = 0x00ff0001;\r
+       static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;\r
+\r
+       final private Handler mHandler = new Handler();\r
+\r
+       final private Runnable mRequestFocus = new Runnable() {\r
+               public void run() {\r
+                       mList.focusableViewAvailable(mList);\r
+               }\r
+       };\r
+\r
+       final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {\r
+               public void onItemClick(AdapterView<?> parent, View v, int position, long id) {\r
+                       onListItemClick((ListView) parent, v, position, id);\r
+               }\r
+       };\r
+\r
+       ExpandableListAdapter mAdapter;\r
+       ExpandableListView mList;\r
+       View mEmptyView;\r
+       TextView mStandardEmptyView;\r
+       View mListContainer;\r
+       boolean mSetEmptyText;\r
+       boolean mListShown;\r
+       boolean mFinishedStart = false;\r
+\r
+       public ExpandableListFragment() {\r
+       }\r
+\r
+       /**\r
+        * Provide default implementation to return a simple list view. Subclasses\r
+        * can override to replace with their own layout. If doing so, the\r
+        * returned view hierarchy <em>must</em> have a ListView whose id\r
+        * is {@link android.R.id#list android.R.id.list} and can optionally\r
+        * have a sibling view id {@link android.R.id#empty android.R.id.empty}\r
+        * that is to be shown when the list is empty.\r
+        * <p/>\r
+        * <p>If you are overriding this method with your own custom content,\r
+        * consider including the standard layout {@link android.R.layout#list_content}\r
+        * in your layout file, so that you continue to retain all of the standard\r
+        * behavior of ListFragment. In particular, this is currently the only\r
+        * way to have the built-in indeterminant progress state be shown.\r
+        */\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
+               FrameLayout root = new FrameLayout(getActivity());\r
+\r
+               FrameLayout lframe = new FrameLayout(getActivity());\r
+               lframe.setId(INTERNAL_LIST_CONTAINER_ID);\r
+\r
+               TextView tv = new TextView(getActivity());\r
+               tv.setId(INTERNAL_EMPTY_ID);\r
+               tv.setGravity(Gravity.CENTER);\r
+               lframe.addView(tv,\r
+                               new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+               ExpandableListView lv = new ExpandableListView(getActivity());\r
+               lv.setId(android.R.id.list);\r
+               lv.setDrawSelectorOnTop(false);\r
+               lv.setOnChildClickListener(this);\r
+               lv.setOnGroupExpandListener(this);\r
+               lv.setOnGroupCollapseListener(this);\r
+\r
+               lframe.addView(lv,\r
+                               new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+               root.addView(lframe, new FrameLayout.LayoutParams(\r
+                               ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+               ListView.LayoutParams lp =\r
+                               new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);\r
+               root.setLayoutParams(lp);\r
+\r
+               return root;\r
+       }\r
+\r
+       /**\r
+        * Attach to list view once the view hierarchy has been created.\r
+        */\r
+       @Override\r
+       public void onViewCreated(View view, Bundle savedInstanceState) {\r
+               super.onViewCreated(view, savedInstanceState);\r
+               ensureList();\r
+       }\r
+\r
+       /** Detach from list view. */\r
+       @Override\r
+       public void onDestroyView() {\r
+               mHandler.removeCallbacks(mRequestFocus);\r
+               mList = null;\r
+               super.onDestroyView();\r
+       }\r
+\r
+       /**\r
+        * This method will be called when an item in the list is selected.\r
+        * Subclasses should override. Subclasses can call\r
+        * getListView().getItemAtPosition(position) if they need to access the\r
+        * data associated with the selected item.\r
+        * @param l The ListView where the click happened\r
+        * @param v The view that was clicked within the ListView\r
+        * @param position The position of the view in the list\r
+        * @param id The row id of the item that was clicked\r
+        */\r
+       public void onListItemClick(ListView l, View v, int position, long id) {\r
+       }\r
+\r
+       /** Provide the cursor for the list view. */\r
+       public void setListAdapter(ExpandableListAdapter adapter) {\r
+               boolean hadAdapter = mAdapter != null;\r
+               mAdapter = adapter;\r
+               if (mList != null) {\r
+                       mList.setAdapter((ExpandableListAdapter) null);\r
+                       mList.setAdapter(adapter);\r
+                       if (!mListShown && !hadAdapter) {\r
+                               // The list was hidden, and previously didn't have an\r
+                               // adapter. It is now time to show it.\r
+                               setListShown(true, getView().getWindowToken() != null);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Set the currently selected list item to the specified\r
+        * position with the adapter's data\r
+        */\r
+       public void setSelection(int position) {\r
+               ensureList();\r
+               mList.setSelection(position);\r
+       }\r
+\r
+       public long getSelectedPosition() {\r
+               ensureList();\r
+               return mList.getSelectedPosition();\r
+       }\r
+\r
+       public long getSelectedId() {\r
+               ensureList();\r
+               return mList.getSelectedId();\r
+       }\r
+\r
+       public ExpandableListView getExpandableListView() {\r
+               ensureList();\r
+               return mList;\r
+       }\r
+\r
+       /**\r
+        * The default content for a ListFragment has a TextView that can\r
+        * be shown when the list is empty. If you would like to have it\r
+        * shown, call this method to supply the text it should use.\r
+        */\r
+       public void setEmptyText(CharSequence text) {\r
+               ensureList();\r
+               if (mStandardEmptyView == null) {\r
+                       throw new IllegalStateException("Can't be used with a custom content view");\r
+               }\r
+               mStandardEmptyView.setText(text);\r
+               if (!mSetEmptyText) {\r
+                       mList.setEmptyView(mStandardEmptyView);\r
+                       mSetEmptyText = true;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Control whether the list is being displayed. You can make it not\r
+        * displayed if you are waiting for the initial data to show in it. During\r
+        * this time an indeterminant progress indicator will be shown instead.\r
+        * <p/>\r
+        * <p>Applications do not normally need to use this themselves. The default\r
+        * behavior of ListFragment is to start with the list not being shown, only\r
+        * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.\r
+        * If the list at that point had not been shown, when it does get shown\r
+        * it will be do without the user ever seeing the hidden state.\r
+        * @param shown If true, the list view is shown; if false, the progress\r
+        * indicator. The initial value is true.\r
+        */\r
+       public void setListShown(boolean shown) {\r
+               setListShown(shown, true);\r
+       }\r
+\r
+       /**\r
+        * Like {@link #setListShown(boolean)}, but no animation is used when\r
+        * transitioning from the previous state.\r
+        */\r
+       public void setListShownNoAnimation(boolean shown) {\r
+               setListShown(shown, false);\r
+       }\r
+\r
+       /**\r
+        * Control whether the list is being displayed. You can make it not\r
+        * displayed if you are waiting for the initial data to show in it. During\r
+        * this time an indeterminant progress indicator will be shown instead.\r
+        * @param shown If true, the list view is shown; if false, the progress\r
+        * indicator. The initial value is true.\r
+        * @param animate If true, an animation will be used to transition to the\r
+        * new state.\r
+        */\r
+       private void setListShown(boolean shown, boolean animate) {\r
+               ensureList();\r
+               if (mListShown == shown) {\r
+                       return;\r
+               }\r
+               mListShown = shown;\r
+               if (mListContainer != null) {\r
+                       if (shown) {\r
+                               if (animate) {\r
+                                       mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));\r
+                               }\r
+                               mListContainer.setVisibility(View.VISIBLE);\r
+                       } else {\r
+                               if (animate) {\r
+                                       mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));\r
+                               }\r
+                               mListContainer.setVisibility(View.GONE);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /** Get the ListAdapter associated with this activity's ListView. */\r
+       public ExpandableListAdapter getExpandableListAdapter() {\r
+               return mAdapter;\r
+       }\r
+\r
+       private void ensureList() {\r
+               if (mList != null) {\r
+                       return;\r
+               }\r
+               View root = getView();\r
+               if (root == null) {\r
+                       throw new IllegalStateException("Content view not yet created");\r
+               }\r
+               if (root instanceof ExpandableListView) {\r
+                       mList = (ExpandableListView) root;\r
+               } else {\r
+                       mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID);\r
+                       if (mStandardEmptyView == null) {\r
+                               mEmptyView = root.findViewById(android.R.id.empty);\r
+                       }\r
+                       mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);\r
+                       View rawListView = root.findViewById(android.R.id.list);\r
+                       if (!(rawListView instanceof ExpandableListView)) {\r
+                               if (rawListView == null) {\r
+                                       throw new RuntimeException("Your content must have a ExpandableListView whose id attribute is " +\r
+                                                       "'android.R.id.list'");\r
+                               }\r
+                               throw new RuntimeException("Content has view with id attribute 'android.R.id.list' " +\r
+                                               "that is not a ExpandableListView class");\r
+                       }\r
+                       mList = (ExpandableListView) rawListView;\r
+                       if (mEmptyView != null) {\r
+                               mList.setEmptyView(mEmptyView);\r
+                       }\r
+               }\r
+               mListShown = true;\r
+               mList.setOnItemClickListener(mOnClickListener);\r
+               if (mAdapter != null) {\r
+                       setListAdapter(mAdapter);\r
+               } else {\r
+                       // We are starting without an adapter, so assume we won't\r
+                       // have our data right away and start with the progress indicator.\r
+                       setListShown(false, false);\r
+               }\r
+               mHandler.post(mRequestFocus);\r
+       }\r
+\r
+       @Override\r
+       public void onGroupExpand(int arg0) {\r
+               // TODO Auto-generated method stub\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onGroupCollapse(int arg0) {\r
+               // TODO Auto-generated method stub\r
+\r
+       }\r
+\r
+       @Override\r
+       public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) {\r
+               // TODO Auto-generated method stub\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\r
+       }\r
+\r
+       public void onContentChanged() {\r
+               View emptyView = getView().findViewById(android.R.id.empty);\r
+               mList = (ExpandableListView) getView().findViewById(android.R.id.list);\r
+               if (mList == null) {\r
+                       throw new RuntimeException(\r
+                                       "Your content must have a ExpandableListView whose id attribute is " + "'android.R.id.list'");\r
+               }\r
+               if (emptyView != null) {\r
+                       mList.setEmptyView(emptyView);\r
+               }\r
+               mList.setOnChildClickListener(this);\r
+               mList.setOnGroupExpandListener(this);\r
+               mList.setOnGroupCollapseListener(this);\r
+\r
+               if (mFinishedStart) {\r
+                       setListAdapter(mAdapter);\r
+               }\r
+               mFinishedStart = true;\r
+       }\r
+}\r
+\r
diff --git a/android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java b/android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java
new file mode 100644 (file)
index 0000000..1cc8e65
--- /dev/null
@@ -0,0 +1,145 @@
+package net.sf.openrocket.android.util;\r
+\r
+/*\r
+ * TODO - this isn't working.\r
+ */\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import android.os.Bundle;\r
+import android.widget.ExpandableListAdapter;\r
+import android.widget.ExpandableListView;\r
+\r
+public class PersistentExpandableListFragment extends ExpandableListFragment {\r
+       private long[] expandedIds;\r
+\r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onCreate");\r
+               super.onCreate(savedInstanceState);\r
+               if ( savedInstanceState != null ) {\r
+                       expandedIds = savedInstanceState.getLongArray("ExpandedIds");\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onStop() {\r
+               AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStop");\r
+               super.onStop();\r
+               expandedIds = getExpandedIds();\r
+       }\r
+\r
+       @Override\r
+    public void onStart() {\r
+               AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStart");\r
+        super.onStart();\r
+        if (this.expandedIds != null) {\r
+            restoreExpandedState(expandedIds);\r
+        }\r
+    }\r
+\r
+       @Override\r
+       public void onPause() {\r
+               AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onPause");\r
+               super.onPause();\r
+               expandedIds = getExpandedIds();\r
+       }\r
+\r
+       \r
+       @Override\r
+       public void onResume() {\r
+               AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onResume");\r
+               super.onResume();\r
+               if (this.expandedIds != null) {\r
+                       restoreExpandedState(expandedIds);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onSaveInstanceState(Bundle outState) {\r
+               super.onSaveInstanceState(outState);\r
+               this.expandedIds = getExpandedIds();\r
+               outState.putLongArray("ExpandedIds", this.expandedIds);\r
+       }\r
+\r
+       /*\r
+    @Override\r
+    protected void onStart() {\r
+        super.onStart();\r
+        if (this.expandedIds != null) {\r
+            restoreExpandedState(expandedIds);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected void onStop() {\r
+        super.onStop();\r
+        expandedIds = getExpandedIds();\r
+    }\r
+\r
+    @Override\r
+    protected void onSaveInstanceState(Bundle outState) {\r
+        super.onSaveInstanceState(outState);\r
+        this.expandedIds = getExpandedIds();\r
+        outState.putLongArray("ExpandedIds", this.expandedIds);\r
+    }\r
+\r
+    @Override\r
+    protected void onRestoreInstanceState(Bundle state) {\r
+        super.onRestoreInstanceState(state);\r
+        long[] expandedIds = state.getLongArray("ExpandedIds");\r
+        if (expandedIds != null) {\r
+            restoreExpandedState(expandedIds);\r
+        }\r
+    }\r
+        */\r
+\r
+\r
+       private long[] getExpandedIds() {\r
+               ExpandableListView list = getExpandableListView();\r
+               ExpandableListAdapter adapter = getExpandableListAdapter();\r
+               if (adapter != null) {\r
+                       int length = adapter.getGroupCount();\r
+                       ArrayList<Long> expandedIds = new ArrayList<Long>();\r
+                       for(int i=0; i < length; i++) {\r
+                               if(list.isGroupExpanded(i)) {\r
+                                       expandedIds.add(adapter.getGroupId(i));\r
+                               }\r
+                       }\r
+                       return toLongArray(expandedIds);\r
+               } else {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       private void restoreExpandedState(long[] expandedIds) {\r
+               this.expandedIds = expandedIds;\r
+               if (expandedIds != null) {\r
+                       ExpandableListView list = getExpandableListView();\r
+                       ExpandableListAdapter adapter = getExpandableListAdapter();\r
+                       if (adapter != null) {\r
+                               for (int i=0; i<adapter.getGroupCount(); i++) {\r
+                                       long id = adapter.getGroupId(i);\r
+                                       if (inArray(expandedIds, id)) list.expandGroup(i);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static boolean inArray(long[] array, long element) {\r
+               for (long l : array) {\r
+                       if (l == element) {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private static long[] toLongArray(List<Long> list)  {\r
+               long[] ret = new long[list.size()];\r
+               int i = 0;\r
+               for (Long e : list)  \r
+                       ret[i++] = e.longValue();\r
+               return ret;\r
+       }\r
+}\r