<?xml version="1.0" encoding="UTF-8"?>\r
<classpath>\r
<classpathentry kind="src" path="gen"/>\r
- <classpathentry excluding="net/sf/openrocket/gui/|net/sf/openrocket/utils/|net/sf/openrocket/file/motor/MotorLoaderHelper.java|net/sf/openrocket/material/MaterialStorage.java|net/sf/openrocket/database/Databases.java" kind="src" path="src"/>\r
+ <classpathentry excluding="net/sf/openrocket/file/motor/MotorLoaderHelper.java|net/sf/openrocket/gui/|net/sf/openrocket/startup/Startup.java|net/sf/openrocket/startup/Startup2.java|net/sf/openrocket/startup/VersionHelper.java|net/sf/openrocket/utils/|net/sf/openrocket/file/motor/|net/sf/openrocket/file/CSVExport.java" kind="src" path="src"/>\r
+ <classpathentry kind="src" path="locale"/>\r
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
<classpathentry kind="lib" path="libs/android-support-v4.jar"/>\r
+ <classpathentry kind="lib" path="libs/Androidplot-core-0.4.4-release.jar"/>\r
<classpathentry kind="output" path="bin/classes"/>\r
</classpath>\r
<?xml version="1.0" encoding="utf-8"?>\r
<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
- package="org.openrocket"\r
+ package="net.sf.openrocket"\r
android:versionCode="1"\r
android:versionName="1.0" >\r
\r
- <uses-sdk android:minSdkVersion="8" />\r
+ <uses-sdk\r
+ android:minSdkVersion="8"\r
+ android:targetSdkVersion="8" />\r
+\r
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
+ <uses-permission android:name="android.permission.INTERNET" />\r
\r
<application\r
+ android:debuggable="true"\r
android:icon="@drawable/ic_launcher"\r
- android:label="@string/app_name" >\r
- <activity\r
- android:label="@string/app_name"\r
- android:name=".OpenRocketSimulation" >\r
+ android:killAfterRestore="true"\r
+ android:label="@string/app_name"\r
+ android:name=".android.Application" >\r
+ <activity android:name=".android.Main" >\r
<intent-filter >\r
<action android:name="android.intent.action.MAIN" />\r
\r
<category android:name="android.intent.category.LAUNCHER" />\r
</intent-filter>\r
</activity>\r
+ <activity\r
+ android:label="@string/app_name"\r
+ android:name=".android.rocket.OpenRocketViewer" >\r
+ <intent-filter >\r
+ <action android:name="android.intent.action.VIEW" />\r
+\r
+ <category android:name="android.intent.category.BROWSABLE" />\r
+ <category android:name="android.intent.category.DEFAULT" />\r
+\r
+ <data\r
+ android:host="*"\r
+ android:pathPattern=".*\\.ork"\r
+ android:scheme="content" />\r
+ <data\r
+ android:host="*"\r
+ android:pathPattern=".*\\.ork"\r
+ android:scheme="file" />\r
+ </intent-filter>\r
+ </activity>\r
+ <activity android:name=".android.PreferencesActivity" >\r
+ <intent-filter >\r
+ <action android:name="net.sf.openrocket.android.PreferencesActivity" />\r
+\r
+ <category android:name="android.intent.category.PREFERENCE" />\r
+ </intent-filter>\r
+ </activity>\r
+ <activity\r
+ android:label="@string/MotorListTitle"\r
+ android:name=".android.motor.MotorHierarchicalBrowser" >\r
+ </activity>\r
+ <activity android:name=".android.motor.MotorDetails" />\r
+ <activity\r
+ android:label="@string/MotorListTitle"\r
+ android:name=".android.thrustcurve.TCQueryActivity" >\r
+ </activity>\r
+ <activity android:name=".android.simulation.SimulationViewer" />\r
</application>\r
\r
</manifest>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
- android:layout_width="fill_parent"\r
- android:layout_height="fill_parent"\r
- android:orientation="vertical" >\r
-\r
- <TextView\r
- android:layout_width="fill_parent"\r
- android:layout_height="wrap_content"\r
- android:text="@string/hello" />\r
-\r
-</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<com.androidplot.xy.XYPlot xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/xyplot"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="0px"
+ android:layout_marginRight="0px"
+ android:layout_marginTop="5px"
+ title="plot"
+/>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <fragment
+ android:id="@+id/burnPlotFragment"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="0px"
+ android:layout_marginRight="0px"
+ android:layout_marginTop="5px"
+ class="net.sf.openrocket.android.motor.BurnPlotFragment"
+ title="Burn Plot" />
+
+ <SlidingDrawer
+ android:id="@+id/drawer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="0.4"
+ android:content="@+id/motorDetailForm"
+ android:handle="@+id/handle" >
+
+ <ImageView
+ android:id="@+id/handle"
+ android:layout_width="match_parent"
+ android:layout_height="30px"
+ android:src="@drawable/arrow_up_float"
+ android:text="" />
+
+ <fragment
+ android:id="@+id/motorDetailForm"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ class="net.sf.openrocket.android.motor.MotorDetailsFragment" />
+ </SlidingDrawer>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/motorDetailForm"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:orientation="vertical"
+ android:paddingTop="10px" >
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Manufacturer" />
+
+ <EditText
+ android:id="@+id/motorDetailsManufacturer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Name" />
+
+ <EditText
+ android:id="@+id/motorDetailsName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Case Info" />
+
+ <EditText
+ android:id="@+id/motorDetailsCaseInfo"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Impulse Class" />
+
+ <EditText
+ android:id="@+id/motorDetailsImpuseClass"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Diameter" />
+
+ <EditText
+ android:id="@+id/motorDetailsDiameter"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:paddingRight="10px"
+ android:text="Length" />
+
+ <EditText
+ android:id="@+id/motorDetailsLength"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.04"
+ android:editable="false" />
+ </TableRow>
+
+</TableLayout>
\ No newline at end of file
--- /dev/null
+<?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
--- /dev/null
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="45dip"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/motorChildManu"
+ android:layout_width="wrap_content"
+ android:layout_height="45dip"
+ android:layout_alignParentLeft="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:textColor="#ffCCCC22"
+ android:textSize="17dip"
+ android:textStyle="bold" >
+ </TextView>
+
+ <TextView
+ android:id="@+id/motorChildName"
+ android:layout_width="wrap_content"
+ android:layout_height="45dip"
+ android:layout_toRightOf="@id/motorChildManu"
+ android:gravity="center_vertical"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:text="Motor Name"
+ android:textColor="#ffCCCC22"
+ android:textSize="17dip"
+ android:textStyle="bold" >
+ </TextView>
+
+ <TextView
+ android:id="@+id/motorChildImpulse"
+ android:layout_width="wrap_content"
+ android:layout_height="45dip"
+ android:layout_alignParentRight="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:text="Motor Impulse"
+ android:textColor="#ffCCCC22"
+ android:textSize="17dip"
+ android:textStyle="bold" >
+ </TextView>
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="45dip" >
+
+ <TextView
+ android:id="@+id/motorGroup"
+ android:layout_width="fill_parent"
+ android:layout_height="45dip"
+ android:gravity="center_vertical|right"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:text="motor group"
+ android:textColor="#ffffffff"
+ android:textSize="17dip"
+ android:textStyle="bold" >
+ </TextView>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+ android:layout_width="fill_parent"\r
+ android:layout_height="fill_parent"\r
+ android:orientation="vertical" >\r
+\r
+ <TextView\r
+ android:id="@+id/heading"\r
+ android:layout_width="fill_parent"\r
+ android:layout_height="wrap_content"\r
+ android:text="Started" />\r
+\r
+ <ListView\r
+ android:id="@+id/rocketSimulations"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="wrap_content" />\r
+\r
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <fragment
+ android:id="@+id/simulationPlotFragment"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="0px"
+ android:layout_marginRight="0px"
+ android:layout_marginTop="5px"
+ class="net.sf.openrocket.android.simulation.SimulationPlotFragment"
+ title="Simulation" />
+
+ <SlidingDrawer
+ android:id="@+id/drawer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="0.4"
+ android:content="@+id/simulationConfigurationForm"
+ android:handle="@+id/handle" >
+
+ <ImageView
+ android:id="@+id/handle"
+ android:layout_width="match_parent"
+ android:layout_height="30px"
+ android:src="@drawable/arrow_up_float"
+ android:text="" />
+
+ <TabHost
+ android:id="@+id/simulationConfigurationForm"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@android:color/black" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <ListView
+ android:id="@+id/simulationEventsList"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <ListView
+ android:id="@+id/simulationSeriesList"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+ </SlidingDrawer>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TableLayout
+ android:id="@+id/tableLayout1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:stretchColumns="1" >
+
+ <TableRow >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:text="@string/TCMotorSearchFormManufacturer" />
+
+ <Spinner
+ android:id="@+id/TCMotorSearchFormManufacturerField"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:entries="@array/TCMotorSearchManufacturerList" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:text="@string/TCMotorSearchFormImpulse" />
+
+ <Spinner
+ android:id="@+id/TCMotorSearchFormImpulseField"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:entries="@array/TCMotorSearchImpulseList" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:text="@string/TCMotorSearchFormCommonName" />
+
+ <EditText
+ android:id="@+id/TCMotorSearchFormCommonNameField"
+ android:text="" />
+ </TableRow>
+
+ <TableRow >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:text="@string/TCMotorSearchFormDiameter" />
+
+ <Spinner
+ android:id="@+id/TCMotorSearchFormDiameterField"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:entries="@array/TCMotorSearchDiameterList" />
+ </TableRow>
+ </TableLayout>
+
+ <Button
+ android:id="@+id/TCMotorSearchFromSubmitButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerInParent="true"
+ android:text="@string/TCMotorSearchFormSubmit" />
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null
+<?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>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:enabled="true" android:id="@+id/save" android:visible="true" android:title="@string/save"/>
+
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
+
+ <item android:title="Motor List" android:id="@+id/motor_list_menu_option"/>\r
+ <item android:title="Preferences" android:id="@+id/preference_menu_option"/>\r
+ \r
+\r
+</menu>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:title="Select Events" android:id="@+id/simulation_select_events_menu_option"/>
+ <item android:title="Select Series" android:id="@+id/simulation_select_series_menu_option"/>
+ <item android:title="Preferences" android:id="@+id/preference_menu_option"/>
+</menu>
<?xml version="1.0" encoding="utf-8"?>\r
<resources>\r
\r
- <string name="hello">Hello World, OpenRocketSimulation!</string>\r
- <string name="app_name">OpenRocketSimulation</string>\r
+ <string name="app_name">OpenRocket</string>\r
+ <string name="save">Save</string>\r
+ <string name="MotorListTitle">Motor List</string>\r
+ <string name="PreferenceMotorBrowserGroupingOption">PreferenceMotorBrowserGroupingOption</string>\r
+\r
+ <string-array name="PreferenceMotorBrowserGroupingEntries">\r
+ <item>Case</item>\r
+ <item>Diameter</item>\r
+ <item>Impulse</item>\r
+ <item>Manufacturer</item>\r
+ </string-array>\r
+ <string-array name="PreferenceMotorBrowserGroupingValues">\r
+ <item>0</item>\r
+ <item>1</item>\r
+ <item>2</item>\r
+ <item>3</item>\r
+ </string-array>\r
+\r
+ <string name="TCMotorSearchFormImpulse">Impulse</string>\r
+\r
+ <string-array name="TCMotorSearchImpulseList">\r
+ <item>All</item>\r
+ <item>A</item>\r
+ <item>B</item>\r
+ <item>C</item>\r
+ <item>D</item>\r
+ <item>E</item>\r
+ <item>F</item>\r
+ <item>G</item>\r
+ <item>H</item>\r
+ <item>I</item>\r
+ <item>J</item>\r
+ <item>K</item>\r
+ <item>L</item>\r
+ <item>M</item>\r
+ <item>N</item>\r
+ <item>O</item>\r
+ </string-array>\r
+\r
+ <string name="TCMotorSearchFormManufacturer">Manufacturer</string>\r
+\r
+ <string-array name="TCMotorSearchManufacturerList">\r
+ <item>All</item>\r
+ <item>AeroTech</item>\r
+ <item>Alpha Hybrids</item>\r
+ <item>Animal Motor Works</item>\r
+ <item>Apogee Components</item>\r
+ <item>Cesaroni Technology</item>\r
+ <item>Contrail Rockets</item>\r
+ <item>Ellis Mountain</item>\r
+ <item>Estes Industries</item>\r
+ <item>Gorilla Rocket Motors</item>\r
+ <item>Hypertek</item>\r
+ <item>Kosdon by AeroTech</item>\r
+ <item>Kosdon TRM</item>\r
+ <item>Loki Research</item>\r
+ <item>Propulsion Polymers</item>\r
+ <item>Public Missiles, Ltd.</item>\r
+ <item>Quest Aerospace</item>\r
+ <item>R.A.T.T. Works</item>\r
+ <item>Roadrunner Rocketry</item>\r
+ <item>Rocketvision Flight-Star</item>\r
+ <item>Sky Ripper Systems</item>\r
+ <item>West Coast Hybrids</item>\r
+ </string-array>\r
+\r
+ <string name="TCMotorSearchFormCommonName">Common Name</string>\r
+ <string name="TCMotorSearchFormDiameter">Diameter</string>\r
+\r
+ <string-array name="TCMotorSearchDiameterList">\r
+ <item>All</item>\r
+ <item>6</item>\r
+ <item>10.5</item>\r
+ <item>13</item>\r
+ <item>18</item>\r
+ <item>20</item>\r
+ <item>24</item>\r
+ <item>29</item>\r
+ <item>32</item>\r
+ <item>38</item>\r
+ <item>54</item>\r
+ <item>64</item>\r
+ <item>69</item>\r
+ <item>75</item>\r
+ <item>76</item>\r
+ <item>81</item>\r
+ <item>98</item>\r
+ <item>152</item>\r
+ <item>161</item>\r
+ </string-array>\r
+\r
+ <string name="TCMotorSearchFormSubmit">Submit</string>\r
+ <string name="tcdownload">Download from ThrustCurve</string>\r
\r
</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ android:key="preferences"
+ android:title="Pref Title"
+ android:summary="pref summary"
+
+
+ <ListPreference
+ android:defaultValue="1"
+ android:entries="@array/PreferenceMotorBrowserGroupingEntries"
+ android:entryValues="@array/PreferenceMotorBrowserGroupingValues"
+ android:key="@string/PreferenceMotorBrowserGroupingOption"
+ android:summary="Set the grouping in Motor Browser"
+ android:title="Motor Browser Group" />
+
+</PreferenceScreen>
\ No newline at end of file
--- /dev/null
+package net.sf.openrocket.android;\r
+\r
+import java.util.Locale;\r
+\r
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.l10n.DebugTranslator;\r
+import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
+import net.sf.openrocket.l10n.Translator;\r
+\r
+public class Application extends android.app.Application {\r
+\r
+ private OpenRocketDocument rocketDocument;\r
+ \r
+ // Big B boolean so I can synchronize on it.\r
+ private static Boolean initialized = false;\r
+ \r
+ public static void initialize() {\r
+ synchronized (initialized) {\r
+ if ( initialized == true ) {\r
+ return;\r
+ }\r
+\r
+ // Android does not have a default sax parser set. This needs to be defined first.\r
+ System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");\r
+\r
+ net.sf.openrocket.startup.Application.setLogger( new LogHelper() );\r
+ \r
+ net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() );\r
+ \r
+ ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(false) {\r
+ \r
+ @Override\r
+ protected void loadMotors() {\r
+ }\r
+ };\r
+ db.startLoading();\r
+\r
+ net.sf.openrocket.startup.Application.setMotorSetDatabase(db);\r
+ \r
+ Translator t;\r
+ t = new ResourceBundleTranslator("l10n.messages");\r
+ if (Locale.getDefault().getLanguage().equals("xx")) {\r
+ t = new DebugTranslator(t);\r
+ }\r
+ \r
+ net.sf.openrocket.startup.Application.setBaseTranslator(t);\r
+\r
+ initialized = true;\r
+ }\r
+ }\r
+\r
+ public Application() {\r
+ initialize();\r
+ }\r
+\r
+ /**\r
+ * @return the rocketDocument\r
+ */\r
+ public OpenRocketDocument getRocketDocument() {\r
+ return rocketDocument;\r
+ }\r
+\r
+ /**\r
+ * @param rocketDocument the rocketDocument to set\r
+ */\r
+ public void setRocketDocument(OpenRocketDocument rocketDocument) {\r
+ this.rocketDocument = rocketDocument;\r
+ }\r
+ \r
+ \r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android;\r
+\r
+import android.util.Log;\r
+import net.sf.openrocket.logging.LogLevel;\r
+import net.sf.openrocket.logging.LogLine;\r
+\r
+\r
+public class LogHelper extends net.sf.openrocket.logging.LogHelper {\r
+\r
+ /* (non-Javadoc)\r
+ * @see net.sf.openrocket.logging.LogHelper#log(net.sf.openrocket.logging.LogLine)\r
+ */\r
+ @Override\r
+ public void log(LogLine line) {\r
+ \r
+ LogLevel level = line.getLevel();\r
+ \r
+ switch ( level ) {\r
+ case ERROR:\r
+ Log.e("OpenRocket", line.toString());\r
+ break;\r
+ case WARN:\r
+ Log.w("OpenRocket", line.toString());\r
+ break;\r
+ case INFO:\r
+ Log.i("OpenRocket", line.toString());\r
+ break;\r
+ case DEBUG:\r
+ Log.d("OpenRocket", line.toString());\r
+ break;\r
+ default:\r
+ Log.v("OpenRocket", line.toString());\r
+ }\r
+ }\r
+\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android;\r
+\r
+import android.app.Activity;\r
+\r
+public class Main extends Activity {\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android;\r
+\r
+import net.sf.openrocket.R;\r
+import android.os.Bundle;\r
+\r
+public class PreferencesActivity extends android.preference.PreferenceActivity {\r
+\r
+ @Override\r
+ protected void onCreate( Bundle savedInstanceState ) {\r
+ super.onCreate( savedInstanceState );\r
+ addPreferencesFromResource(R.xml.preferences);\r
+ }\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android;\r
+\r
+import java.util.Collections;\r
+import java.util.Set;\r
+\r
+import net.sf.openrocket.material.Material;\r
+\r
+public class PreferencesAdapter extends net.sf.openrocket.startup.Preferences {\r
+\r
+ @Override\r
+ public boolean getBoolean(String key, boolean defaultValue) {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public void putBoolean(String key, boolean value) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public int getInt(String key, int defaultValue) {\r
+ // TODO Auto-generated method stub\r
+ return 0;\r
+ }\r
+\r
+ @Override\r
+ public void putInt(String key, int value) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public double getDouble(String key, double defaultValue) {\r
+ // TODO Auto-generated method stub\r
+ return 0;\r
+ }\r
+\r
+ @Override\r
+ public void putDouble(String key, double value) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public String getString(String key, String defaultValue) {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public void putString(String key, String value) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public String getString(String directory, String key, String defaultValue) {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public void putString(String directory, String key, String value) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see net.sf.openrocket.startup.Preferences#addUserMaterial(net.sf.openrocket.material.Material)\r
+ */\r
+ @Override\r
+ public void addUserMaterial(Material m) {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see net.sf.openrocket.startup.Preferences#getUserMaterials()\r
+ */\r
+ @Override\r
+ public Set<Material> getUserMaterials() {\r
+ return Collections.<Material>emptySet();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see net.sf.openrocket.startup.Preferences#removeUserMaterial(net.sf.openrocket.material.Material)\r
+ */\r
+ @Override\r
+ public void removeUserMaterial(Material m) {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.db;\r
+\r
+import android.content.Context;\r
+import android.database.SQLException;\r
+import android.database.sqlite.SQLiteDatabase;\r
+import android.database.sqlite.SQLiteOpenHelper;\r
+import android.util.Log;\r
+\r
+public class DbAdapter {\r
+\r
+ private static final String TAG = "DbAdapter";\r
+ private DatabaseHelper mDbHelper;\r
+ private SQLiteDatabase mDb;\r
+\r
+ private static final String DATABASE_NAME = "rocketflightnotebook";\r
+ private static final int DATABASE_VERSION = 5;\r
+\r
+ private final Context mCtx;\r
+\r
+ private MotorDao motorDao;\r
+ \r
+ public MotorDao getMotorDao() {\r
+ return motorDao;\r
+ }\r
+ \r
+ private class DatabaseHelper extends SQLiteOpenHelper {\r
+ DatabaseHelper(Context context) {\r
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);\r
+ }\r
+\r
+ @Override\r
+ public void onCreate(SQLiteDatabase db) {\r
+ executeSQL( db, MotorDao.create());\r
+ }\r
+ \r
+ @Override\r
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
+ Log.w(TAG, "Upgrading database from version " + oldVersion + " to "\r
+ + newVersion + ", which will destroy all old data");\r
+ executeSQL(db, MotorDao.update(oldVersion, newVersion));\r
+ }\r
+\r
+ private void executeSQL( SQLiteDatabase db, String[] sqls ) {\r
+ for(String s: sqls ) {\r
+ db.execSQL(s);\r
+ }\r
+ }\r
+\r
+ }\r
+ \r
+ /**\r
+ * Constructor - takes the context to allow the database to be\r
+ * opened/created\r
+ * \r
+ * @param ctx the Context within which to work\r
+ */\r
+ public DbAdapter(Context ctx) {\r
+ this.mCtx = ctx;\r
+ }\r
+\r
+ /**\r
+ * Open the database. If it cannot be opened, try to create a new\r
+ * instance of the database. If it cannot be created, throw an exception to\r
+ * signal the failure\r
+ * \r
+ * @return this (self reference, allowing this to be chained in an\r
+ * initialization call)\r
+ * @throws SQLException if the database could be neither opened or created\r
+ */\r
+ public DbAdapter open() throws SQLException {\r
+ mDbHelper = new DatabaseHelper(mCtx);\r
+ mDb = mDbHelper.getWritableDatabase();\r
+ motorDao = new MotorDao(mDb);\r
+ return this;\r
+ }\r
+\r
+ public void close() {\r
+ mDbHelper.close();\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+package net.sf.openrocket.android.db;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.ObjectInputStream;\r
+import java.io.ObjectOutputStream;\r
+import java.util.Vector;\r
+\r
+import net.sf.openrocket.android.motor.Motor;\r
+import android.content.ContentValues;\r
+import android.database.Cursor;\r
+import android.database.SQLException;\r
+import android.database.sqlite.SQLiteDatabase;\r
+import android.util.Log;\r
+\r
+public class MotorDao {\r
+\r
+ private static final String TAG = "MotorDao";\r
+\r
+ private SQLiteDatabase mDb;\r
+\r
+ private final static String DATABASE_TABLE = "motor";\r
+ private final static String DROP_TABLE = "DROP TABLE IF EXISTS " + DATABASE_TABLE;\r
+ private final static String CREATE_TABLE =\r
+ "create table "+ DATABASE_TABLE + " ( " +\r
+ "_id integer primary key, "+\r
+ "unique_name text unique, "+\r
+ "name text, "+\r
+ "diameter number, "+\r
+ "tot_impulse_ns number, "+\r
+ "avg_thrust_n number, "+\r
+ "max_thrust_n number, "+\r
+ "burn_time_s number, "+\r
+ "length number," +\r
+ "prop_mass_g number,"+\r
+ "tot_mass_g number,"+\r
+ "case_info text,"+\r
+ "manufacturer text," +\r
+ "impulse_class text," +\r
+ "burndata blob"+\r
+ ");";\r
+\r
+ MotorDao( SQLiteDatabase mDb ) {\r
+ this.mDb = mDb;\r
+ }\r
+\r
+ static String[] create() { return new String[] {CREATE_TABLE}; }\r
+\r
+ static String[] update( int oldVer, int newVer ) {\r
+ return new String[] { DROP_TABLE, CREATE_TABLE };\r
+ }\r
+\r
+ public final static String ID = "_id";\r
+ public final static String UNIQUE_NAME = "unique_name";\r
+ public final static String NAME = "name";\r
+ public final static String DIAMETER = "diameter";\r
+ public final static String TOTAL_IMPULSE = "tot_impulse_ns"; \r
+ public final static String AVG_THRUST = "avg_thrust_n";\r
+ public final static String MAX_THRUST = "max_thrust_n";\r
+ public final static String BURN_TIME = "burn_time_s";\r
+ public final static String LENGTH = "length";\r
+ public final static String PROP_MASS = "prop_mass_g";\r
+ public final static String TOT_MASS = "tot_mass_g";\r
+ public final static String BURNDATA = "burndata";\r
+ public final static String CASE_INFO = "case_info";\r
+ public final static String MANUFACTURER = "manufacturer";\r
+ public final static String IMPULSE_CLASS = "impulse_class";\r
+\r
+ public long insertOrUpdateMotor(Motor mi) {\r
+ ContentValues initialValues = new ContentValues();\r
+ initialValues.put(ID, mi.getMotor_id());\r
+ initialValues.put(NAME, mi.getName());\r
+ initialValues.put(DIAMETER,mi.getDiameter());\r
+ initialValues.put(TOTAL_IMPULSE,mi.getTotalImpulse());\r
+ initialValues.put(AVG_THRUST,mi.getAvgThrust());\r
+ initialValues.put(MAX_THRUST,mi.getMaxThrust());\r
+ initialValues.put(BURN_TIME,mi.getBurnTime());\r
+ initialValues.put(LENGTH, mi.getLength());\r
+ initialValues.put(PROP_MASS, mi.getPropMass());\r
+ initialValues.put(TOT_MASS,mi.getTotMass());\r
+ initialValues.put(CASE_INFO, mi.getCaseInfo());\r
+ initialValues.put(MANUFACTURER,mi.getManufacturer());\r
+ initialValues.put(IMPULSE_CLASS,mi.getImpulseClass());\r
+ initialValues.put(UNIQUE_NAME, mi.getManufacturer()+mi.getName());\r
+ {\r
+ // Serialize the Vector of burn data\r
+ Vector<Double> burndata = mi.getBurndata();\r
+ byte[] serObj = null;\r
+ if ( burndata != null ) {\r
+ try {\r
+ ByteArrayOutputStream b = new ByteArrayOutputStream();\r
+ ObjectOutputStream os = new ObjectOutputStream(b);\r
+ os.writeObject(burndata);\r
+ os.close();\r
+ serObj = b.toByteArray();\r
+ } catch (Exception ex) {\r
+ Log.d(TAG,"unable to serialze burndata");\r
+ }\r
+ }\r
+ initialValues.put(BURNDATA, serObj);\r
+ }\r
+\r
+\r
+ Log.d(TAG,"insertOrUpdate Motor");\r
+ long rv = mDb.insertWithOnConflict(DATABASE_TABLE, null, initialValues,SQLiteDatabase.CONFLICT_REPLACE);\r
+ return rv;\r
+ }\r
+\r
+ /**\r
+ * Delete the motor and burn data with the given rowId\r
+ * \r
+ * @param name name of motor to delete\r
+ * @return true if deleted, false otherwise\r
+ */\r
+ public boolean deleteMotor(Long id) {\r
+\r
+ boolean rv = mDb.delete(DATABASE_TABLE, ID + "=" + id, null) > 0;\r
+ return rv;\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param groupCol\r
+ * @param groupVal\r
+ * @return\r
+ */\r
+ public Cursor fetchAllInGroups( String groupCol, String groupVal ) {\r
+ return mDb.query(DATABASE_TABLE, \r
+ /* columns */new String[] {\r
+ ID,\r
+ NAME,\r
+ DIAMETER ,\r
+ TOTAL_IMPULSE,\r
+ AVG_THRUST ,\r
+ MAX_THRUST ,\r
+ BURN_TIME ,\r
+ LENGTH,\r
+ PROP_MASS,\r
+ TOT_MASS,\r
+ CASE_INFO,\r
+ IMPULSE_CLASS,\r
+ MANUFACTURER\r
+ },\r
+ /* selection */groupCol + "=?",\r
+ /* selection args*/new String[] {groupVal},\r
+ /* groupby */null,\r
+ /* having*/null,\r
+ /* orderby*/ NAME );\r
+\r
+ }\r
+\r
+ /**\r
+ * Fetch the groups based on groupCol\r
+ * @param groupCol\r
+ * @return\r
+ */\r
+ public Cursor fetchGroups( String groupCol ) {\r
+ return mDb.query(true, DATABASE_TABLE, \r
+ /* columns */new String[] {\r
+ groupCol\r
+ },\r
+ /* selection */null,\r
+ /* selection args*/null,\r
+ /* groupby */null,\r
+ /* having*/null,\r
+ /* orderby*/null,\r
+ /* limit*/ null);\r
+\r
+ }\r
+\r
+ /**\r
+ * Return a Cursor over the list of all motors\r
+ * \r
+ * @return Cursor over all notes\r
+ */\r
+ public Cursor fetchAllMotors() {\r
+\r
+ return mDb.query(DATABASE_TABLE, \r
+ /* columns */new String[] {\r
+ ID,\r
+ NAME,\r
+ DIAMETER ,\r
+ TOTAL_IMPULSE,\r
+ AVG_THRUST ,\r
+ MAX_THRUST ,\r
+ BURN_TIME ,\r
+ LENGTH,\r
+ PROP_MASS,\r
+ TOT_MASS,\r
+ CASE_INFO,\r
+ IMPULSE_CLASS,\r
+ MANUFACTURER\r
+ },\r
+ /* selection */null,\r
+ /* selection args*/null,\r
+ /* groupby */null,\r
+ /* having*/null,\r
+ /* orderby*/null);\r
+ }\r
+\r
+ public Motor fetchMotor(Long id ) throws SQLException {\r
+ Cursor mCursor = mDb.query(DATABASE_TABLE, \r
+ /* columns */new String[] {\r
+ ID,\r
+ NAME ,\r
+ DIAMETER ,\r
+ TOTAL_IMPULSE ,\r
+ AVG_THRUST ,\r
+ MAX_THRUST ,\r
+ BURN_TIME ,\r
+ LENGTH,\r
+ PROP_MASS,\r
+ TOT_MASS,\r
+ CASE_INFO,\r
+ IMPULSE_CLASS,\r
+ MANUFACTURER,\r
+ BURNDATA\r
+ },\r
+ /* selection */ID + "="+id,\r
+ /* selection args*/null,\r
+ /* groupby */null,\r
+ /* having*/null,\r
+ /* orderby*/null);\r
+ if ( mCursor == null ) {\r
+ return null;\r
+ }\r
+ try {\r
+ if (mCursor.getCount() == 0) {\r
+ return null;\r
+ }\r
+ mCursor.moveToFirst();\r
+ Motor mi = new Motor();\r
+ mi.setMotor_id(mCursor.getLong(mCursor.getColumnIndex(ID)));\r
+ mi.setName(mCursor.getString(mCursor.getColumnIndex(NAME)));\r
+ mi.setDiameter(mCursor.getLong(mCursor.getColumnIndex(DIAMETER)));\r
+ mi.setTotalImpulse(mCursor.getFloat(mCursor.getColumnIndex(TOTAL_IMPULSE)));\r
+ mi.setAvgThrust(mCursor.getFloat(mCursor.getColumnIndex(AVG_THRUST)));\r
+ mi.setMaxThrust(mCursor.getFloat(mCursor.getColumnIndex(MAX_THRUST)));\r
+ mi.setBurnTime(mCursor.getFloat(mCursor.getColumnIndex(BURN_TIME)));\r
+ mi.setLength(mCursor.getFloat(mCursor.getColumnIndex(LENGTH)));\r
+ mi.setPropMass(mCursor.getDouble(mCursor.getColumnIndex(PROP_MASS)));\r
+ mi.setCaseInfo(mCursor.getString(mCursor.getColumnIndex(CASE_INFO)));\r
+ mi.setTotMass(mCursor.getDouble(mCursor.getColumnIndex(TOT_MASS)));\r
+ mi.setManufacturer(mCursor.getString(mCursor.getColumnIndex(MANUFACTURER)));\r
+ mi.setImpulseClass(mCursor.getString(mCursor.getColumnIndex(IMPULSE_CLASS)));\r
+\r
+ {\r
+ // Deserialize burndata column\r
+ byte[] serObj = mCursor.getBlob(mCursor.getColumnIndex(BURNDATA));\r
+ Vector<Double> burndata = null;\r
+ if (serObj != null ) {\r
+ try {\r
+ ObjectInputStream is = new ObjectInputStream( new ByteArrayInputStream(serObj));\r
+ burndata = (Vector<Double>) is.readObject();\r
+ }\r
+ catch (Exception ex) {\r
+ Log.d(TAG,"cannot deserialize burndata");\r
+ }\r
+ }\r
+ mi.setBurndata(burndata);\r
+ }\r
+ return mi;\r
+ }\r
+ finally {\r
+ mCursor.close();\r
+ }\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.motor;\r
+\r
+import java.util.Vector;\r
+\r
+import net.sf.openrocket.R;\r
+import android.app.Activity;\r
+import android.graphics.Color;\r
+import android.graphics.PointF;\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.MotionEvent;\r
+import android.view.ScaleGestureDetector;\r
+import android.view.View;\r
+import android.view.View.OnTouchListener;\r
+import android.view.ViewGroup;\r
+\r
+import com.androidplot.xy.BoundaryMode;\r
+import com.androidplot.xy.LineAndPointFormatter;\r
+import com.androidplot.xy.LineAndPointRenderer;\r
+import com.androidplot.xy.SimpleXYSeries;\r
+import com.androidplot.xy.XYPlot;\r
+import com.androidplot.xy.YValueMarker;\r
+\r
+public class BurnPlotFragment extends Fragment implements OnTouchListener {\r
+\r
+ private final static String TAG = "BurnPlotFragment";\r
+\r
+ private XYPlot mySimpleXYPlot;\r
+ private SimpleXYSeries mySeries;\r
+ private PointF minXY;\r
+ private PointF maxXY;\r
+ \r
+ private float absMinX;\r
+ private float absMaxX;\r
+ private float minNoError;\r
+ private float maxNoError;\r
+\r
+ private ScaleGestureDetector mScaleDetector;\r
+ private float mScaleFactor = 1.f;\r
+\r
+ public static BurnPlotFragment initializeBurnPlotHelper( Motor motor ) {\r
+ BurnPlotFragment h = new BurnPlotFragment();\r
+\r
+ Bundle args = new Bundle();\r
+ args.putSerializable("Motor", motor);\r
+ h.setArguments(args);\r
+ return h;\r
+ }\r
+\r
+ @Override\r
+ public void onAttach(Activity activity) {\r
+ super.onAttach(activity);\r
+ Log.d(TAG,"onAttach");\r
+ }\r
+\r
+ @Override\r
+ public void onCreate(Bundle savedInstanceState) {\r
+ Log.d(TAG,"onCreate");\r
+ super.onCreate(savedInstanceState);\r
+ }\r
+\r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ Log.d(TAG,"onCreateView");\r
+ View v = inflater.inflate(R.layout.motor_burn, container, false);\r
+ mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);\r
+ mySimpleXYPlot.setOnTouchListener(this);\r
+ mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());\r
+ // Motor motor = getMotor();\r
+ // init(motor);\r
+ return v;\r
+ }\r
+\r
+ void init( Motor motor ) {\r
+\r
+ mySimpleXYPlot.setUserDomainOrigin(0);\r
+ mySimpleXYPlot.setUserRangeOrigin(0);\r
+ mySimpleXYPlot.setRangeLabel("impuse (n)");\r
+ mySimpleXYPlot.setDomainLabel("time (s)");\r
+ mySimpleXYPlot.addMarker(new YValueMarker(motor.getAvgThrust(),"average" ));\r
+ mySimpleXYPlot.disableAllMarkup();\r
+\r
+ Vector<Double> data = null;\r
+ try {\r
+ data = motor.getBurndata();\r
+ } catch ( Exception ex ) {\r
+ }\r
+ if ( data == null || data.size() == 0 ) {\r
+ data = new Vector<Double>();\r
+ data.add(0.0);\r
+ data.add(0.0);\r
+ data.add(1.0);\r
+ data.add(1.0);\r
+ }\r
+ Log.d("plot","data = " + data.toString());\r
+\r
+ mySeries = new SimpleXYSeries(data, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED,motor.getName());\r
+\r
+ mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,\r
+ new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null));\r
+\r
+ //Set of internal variables for keeping track of the boundaries\r
+ mySimpleXYPlot.calculateMinMaxVals();\r
+ \r
+ mySimpleXYPlot.redraw();\r
+\r
+ minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());\r
+ maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());\r
+\r
+ absMinX = minXY.x;\r
+ absMaxX = maxXY.x;\r
+ \r
+ minNoError = Math.round(mySeries.getX(1).floatValue() +2);\r
+ maxNoError = Math.round(mySeries.getX(mySeries.size() -1).floatValue()) - 2.0f;\r
+ }\r
+\r
+ private float mPosX;\r
+ private float mPosY;\r
+\r
+ private float mLastTouchX;\r
+ private float mLastTouchY;\r
+\r
+ private int mActivePointerId = -1;\r
+\r
+ @Override\r
+ public boolean onTouch(View arg0, MotionEvent event) {\r
+ mScaleDetector.onTouchEvent(event);\r
+\r
+ final int action = event.getAction();\r
+ switch ( action & MotionEvent.ACTION_MASK ) {\r
+ case MotionEvent.ACTION_DOWN: {\r
+ final float x = event.getX();\r
+ final float y = event.getY();\r
+\r
+ mLastTouchX = x;\r
+ mLastTouchY = y;\r
+\r
+ mActivePointerId = event.getPointerId(0);\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_MOVE: {\r
+ final int pointerIndex = event.findPointerIndex(mActivePointerId);\r
+ final float x = event.getX(pointerIndex);\r
+ final float y = event.getY(pointerIndex);\r
+\r
+ if (!mScaleDetector.isInProgress()) {\r
+ final float dx = x - mLastTouchX;\r
+ final float dy = y - mLastTouchY;\r
+ \r
+ mPosX += dx;\r
+ mPosY += dy;\r
+ scroll(dx);\r
+ // do scroll.\r
+ \r
+ }\r
+ mLastTouchX = x;\r
+ mLastTouchY = y;\r
+ \r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_UP: {\r
+ mActivePointerId = -1;\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_CANCEL: {\r
+ mActivePointerId = -1;\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_POINTER_UP: {\r
+ final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;\r
+ final int pointerId = event.getPointerId(pointerIndex);\r
+ if (pointerId == mActivePointerId) {\r
+ // This was our active pointer going up. choose a new active pointer and adjust accordingly.\r
+ final int newPointerIndex = pointerIndex ==0 ? 1:0;\r
+ mLastTouchX = event.getX(newPointerIndex);\r
+ mLastTouchY = event.getY(newPointerIndex);\r
+ mActivePointerId = event.getPointerId(newPointerIndex);\r
+ }\r
+ break;\r
+ }\r
+ } \r
+ return true;\r
+ }\r
+\r
+ private void zoom(float scale) {\r
+ Log.d(TAG,"zoom by " + scale);\r
+ float domainSpan = absMaxX - absMinX;\r
+ Log.d(TAG,"domainSpan = " + domainSpan);\r
+ float domainMidPoint = absMaxX - domainSpan / 2.0f;\r
+ Log.d(TAG,"domainMidPoint = " + domainMidPoint);\r
+ float offset = domainSpan / scale;\r
+ Log.d(TAG,"offset " + offset);\r
+ minXY.x=domainMidPoint- offset;\r
+ Log.d(TAG,"min X " + minXY.x);\r
+ maxXY.x=domainMidPoint+offset;\r
+ Log.d(TAG,"max X " + maxXY.x);\r
+ checkBoundaries();\r
+ mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
+ mySimpleXYPlot.redraw();\r
+ }\r
+\r
+ private void scroll(float pan) {\r
+ float domainSpan = maxXY.x - minXY.x;\r
+ float step = domainSpan / mySimpleXYPlot.getWidth();\r
+ float offset = pan * step;\r
+ minXY.x+= offset;\r
+ maxXY.x+= offset;\r
+ checkBoundaries();\r
+ mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
+ mySimpleXYPlot.redraw();\r
+ }\r
+\r
+ private void checkBoundaries() {\r
+ \r
+ if ( minXY.x < absMinX) \r
+ minXY.x = absMinX;\r
+// else if ( minXY.x > maxNoError )\r
+// minXY.x = maxNoError;\r
+ \r
+ if ( maxXY.x > absMaxX)\r
+ maxXY.x = absMaxX;\r
+// else if ( maxXY.x < minNoError)\r
+// maxXY.x = minNoError;\r
+ }\r
+ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {\r
+ @Override\r
+ public boolean onScale( ScaleGestureDetector detector ) {\r
+ mScaleFactor *= detector.getScaleFactor();\r
+\r
+ mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));\r
+ zoom(mScaleFactor);\r
+ return true;\r
+ }\r
+ }\r
+}\r
+\r
--- /dev/null
+package net.sf.openrocket.android.motor;\r
+\r
+import java.io.Serializable;\r
+import java.util.Vector;\r
+\r
+public class Motor implements Serializable {\r
+ \r
+ private Long motor_id;\r
+ private String name;\r
+ private String impulseClass;\r
+ private String manufacturer;\r
+ private Long diameter;\r
+ private String caseInfo;\r
+ private Float avgThrust;\r
+ private Float maxThrust;\r
+ private Float totalImpulse;\r
+ private Float burnTime;\r
+ private Float length;\r
+ private Double propMass;\r
+ private Double totMass;\r
+ private Vector<Double> burndata;\r
+ public Long getMotor_id() {\r
+ return motor_id;\r
+ }\r
+ public void setMotor_id(Long motor_id) {\r
+ this.motor_id = motor_id;\r
+ }\r
+ public String getName() {\r
+ return name;\r
+ }\r
+ public void setName(String name) {\r
+ this.name = name;\r
+ }\r
+ public String getImpulseClass() {\r
+ return impulseClass;\r
+ }\r
+ public void setImpulseClass(String impulseClass) {\r
+ this.impulseClass = impulseClass;\r
+ }\r
+ public String getManufacturer() {\r
+ return manufacturer;\r
+ }\r
+ public void setManufacturer(String manufacturer) {\r
+ this.manufacturer = manufacturer;\r
+ }\r
+ public Long getDiameter() {\r
+ return diameter;\r
+ }\r
+ public void setDiameter(Long diameter) {\r
+ this.diameter = diameter;\r
+ }\r
+ public String getCaseInfo() {\r
+ return caseInfo;\r
+ }\r
+ public void setCaseInfo(String caseInfo) {\r
+ this.caseInfo = caseInfo;\r
+ }\r
+ public Float getAvgThrust() {\r
+ return avgThrust;\r
+ }\r
+ public void setAvgThrust(Float avgThrust) {\r
+ this.avgThrust = avgThrust;\r
+ }\r
+ public Float getMaxThrust() {\r
+ return maxThrust;\r
+ }\r
+ public void setMaxThrust(Float maxThrust) {\r
+ this.maxThrust = maxThrust;\r
+ }\r
+ public Float getTotalImpulse() {\r
+ return totalImpulse;\r
+ }\r
+ public void setTotalImpulse(Float totalImpulse) {\r
+ this.totalImpulse = totalImpulse;\r
+ }\r
+ public Float getBurnTime() {\r
+ return burnTime;\r
+ }\r
+ public void setBurnTime(Float burnTime) {\r
+ this.burnTime = burnTime;\r
+ }\r
+ public Float getLength() {\r
+ return length;\r
+ }\r
+ public void setLength(Float length) {\r
+ this.length = length;\r
+ }\r
+ public Double getPropMass() {\r
+ return propMass;\r
+ }\r
+ public void setPropMass(Double propMass) {\r
+ this.propMass = propMass;\r
+ }\r
+ public Double getTotMass() {\r
+ return totMass;\r
+ }\r
+ public void setTotMass(Double totMass) {\r
+ this.totMass = totMass;\r
+ }\r
+ public Vector<Double> getBurndata() {\r
+ return burndata;\r
+ }\r
+ public void setBurndata(Vector<Double> burndata) {\r
+ this.burndata = burndata;\r
+ }\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\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 Motor 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
+ motor = (Motor) i.getSerializableExtra("Motor");\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
--- /dev/null
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.EditText;\r
+\r
+public class MotorDetailsFragment extends Fragment {\r
+\r
+ EditText manuField;\r
+ EditText nameField;\r
+ EditText caseField;\r
+ EditText impulseClassField;\r
+ EditText diameterField;\r
+ EditText lengthField;\r
+ \r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ View v = inflater.inflate(R.layout.motor_detail_form, container, false);\r
+ manuField = (EditText) v.findViewById(R.id.motorDetailsManufacturer);\r
+ nameField = (EditText) v.findViewById(R.id.motorDetailsName);\r
+ caseField = (EditText) v.findViewById(R.id.motorDetailsCaseInfo);\r
+ impulseClassField = (EditText) v.findViewById(R.id.motorDetailsImpuseClass);\r
+ diameterField = (EditText) v.findViewById(R.id.motorDetailsDiameter);\r
+ lengthField = (EditText) v.findViewById(R.id.motorDetailsLength);\r
+ return v;\r
+ }\r
+\r
+ public void init( Motor m ) {\r
+ manuField.setText( m.getManufacturer());\r
+ nameField.setText( m.getName() );\r
+ caseField.setText( m.getCaseInfo());\r
+ impulseClassField.setText( m.getImpulseClass());\r
+ diameterField.setText( m.getDiameter().toString() );\r
+ lengthField.setText( m.getLength().toString() );\r
+ \r
+ }\r
+ \r
+}\r
--- /dev/null
+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.SimpleCursorTreeAdapter;\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 SimpleCursorTreeAdapter\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, String[] groupFrom, int[] groupTo, String[] childrenFrom,\r
+ int[] childrenTo) {\r
+\r
+ super(context, cursor, groupLayout, groupFrom, groupTo, childLayout, childrenFrom,\r
+ childrenTo);\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
+ }\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
+ Motor m = mDbHelper.getMotorDao().fetchMotor(id);\r
+ //Intent i = new Intent(this, BurnPlotActivity.class);\r
+ Intent i = new Intent(this,MotorDetails.class);\r
+ i.putExtra("Motor", m);\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
+ new String[] { groupColumn }, // Name for group layouts\r
+ new int[] { R.id.motorGroup },\r
+ new String[] { MotorDao.MANUFACTURER, MotorDao.NAME, MotorDao.TOTAL_IMPULSE }, // Number for child layouts\r
+ new int[] { R.id.motorChildManu, R.id.motorChildName, R.id.motorChildImpulse });\r
+ setListAdapter(mAdapter);\r
+ }\r
+}\r
--- /dev/null
+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
--- /dev/null
+package net.sf.openrocket.android.rocket;\r
+\r
+import java.io.File;\r
+\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.file.RocketLoadException;\r
+import net.sf.openrocket.file.openrocket.OpenRocketLoader;\r
+import android.os.AsyncTask;\r
+import android.util.Log;\r
+\r
+public class OpenRocketLoaderTask extends AsyncTask<File, Void, OpenRocketDocument> {\r
+\r
+ private final static String TAG = "OpenRocketLoaderTask";\r
+ \r
+ /* (non-Javadoc)\r
+ * @see android.os.AsyncTask#doInBackground(Params[])\r
+ */\r
+ @Override\r
+ protected OpenRocketDocument doInBackground(File... arg0) {\r
+ Log.d(TAG,"doInBackgroud");\r
+ \r
+ OpenRocketLoader rocketLoader = new OpenRocketLoader();\r
+ try {\r
+ OpenRocketDocument rocket = rocketLoader.load(arg0[0]);\r
+ return rocket;\r
+ }\r
+ catch( RocketLoadException ex ) {\r
+ Log.e(TAG, "doInBackground rocketLaoder.load threw", ex);\r
+ }\r
+ return null;\r
+ \r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.rocket;\r
+\r
+\r
+import java.io.File;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.PreferencesActivity;\r
+import net.sf.openrocket.android.motor.MotorHierarchicalBrowser;\r
+import net.sf.openrocket.android.simulation.SimulationViewer;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.document.Simulation;\r
+import android.app.Activity;\r
+import android.content.Intent;\r
+import android.net.Uri;\r
+import android.os.Bundle;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.Menu;\r
+import android.view.MenuInflater;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.AdapterView;\r
+import android.widget.AdapterView.OnItemClickListener;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+\r
+public class OpenRocketViewer extends Activity {\r
+\r
+ private static final String TAG = "OpenRocketViewer";\r
+\r
+ TextView header;\r
+ ListView simulationList;\r
+ \r
+ Application app;\r
+\r
+\r
+ /* (non-Javadoc)\r
+ * @see android.app.Activity#onCreate(android.os.Bundle)\r
+ */\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ \r
+ Log.d(TAG,"In onCreate");\r
+ \r
+ app = (Application) this.getApplication();\r
+\r
+ setContentView(R.layout.openrocketviewer);\r
+ \r
+ header = (TextView) findViewById(R.id.heading);\r
+ simulationList = (ListView) findViewById(R.id.rocketSimulations);\r
+\r
+ Intent i = getIntent();\r
+ Uri file = i.getData();\r
+ String path = file.getPath();\r
+ Log.d(TAG,"Use ork file: " + file);\r
+ File orkFile = new File(path);\r
+ final OpenRocketLoaderTask task = new OpenRocketLoaderTask() {\r
+\r
+ /* (non-Javadoc)\r
+ * @see android.os.AsyncTask#onPostExecute(java.lang.Object)\r
+ */\r
+ @Override\r
+ protected void onPostExecute(OpenRocketDocument result) {\r
+ super.onPostExecute(result);\r
+ app.setRocketDocument( result );\r
+ updateContents();\r
+ }\r
+ \r
+ };\r
+ \r
+ task.execute(orkFile);\r
+ }\r
+\r
+ private void updateContents() {\r
+ \r
+ OpenRocketDocument rocket = app.getRocketDocument();\r
+ header.setText( rocket.getRocket().getName());\r
+ \r
+ ArrayAdapter<Simulation> sims = new ArrayAdapter<Simulation>(this,android.R.layout.simple_list_item_1,rocket.getSimulations()) {\r
+\r
+ @Override\r
+ public View getView(int position, View convertView,\r
+ ViewGroup parent) {\r
+ View v = convertView;\r
+ if ( v == null ) {\r
+ LayoutInflater li = getLayoutInflater();\r
+ v = li.inflate(android.R.layout.simple_list_item_1,null);\r
+ }\r
+ Simulation sim = this.getItem(position);\r
+ ((TextView)v.findViewById(android.R.id.text1)).setText( sim.getName() );\r
+ return v;\r
+ }\r
+\r
+ };\r
+ simulationList.setOnItemClickListener( new OnItemClickListener() {\r
+ @Override\r
+ public void onItemClick(AdapterView l, View v, int position, long id) {\r
+ Intent i = new Intent(OpenRocketViewer.this, SimulationViewer.class);\r
+ Log.d(TAG,"onItemClick simulation number " + id );\r
+ i.putExtra("Simulation",(int)id);\r
+ startActivityForResult(i, 1/*magic*/);\r
+ }\r
+ \r
+ });\r
+ simulationList.setAdapter(sims);\r
+\r
+ }\r
+ \r
+ @Override\r
+ public boolean onCreateOptionsMenu(Menu menu) {\r
+ MenuInflater inflater = getMenuInflater();\r
+ inflater.inflate(R.menu.rocket_viewer_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.motor_list_menu_option:\r
+ startMotorBrowser();\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
+ public void startMotorBrowser() {\r
+ Log.d(TAG,"motorBrowserButton clicked");\r
+ Intent i = new Intent(OpenRocketViewer.this, MotorHierarchicalBrowser.class);\r
+ startActivity(i);\r
+ }\r
+\r
+\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.simulation;\r
+\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.simulation.FlightDataBranch;\r
+import net.sf.openrocket.simulation.FlightDataType;\r
+import net.sf.openrocket.simulation.FlightEvent;\r
+import android.app.Activity;\r
+import android.graphics.Color;\r
+import android.graphics.PointF;\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.MotionEvent;\r
+import android.view.ScaleGestureDetector;\r
+import android.view.View;\r
+import android.view.View.OnTouchListener;\r
+import android.view.ViewGroup;\r
+\r
+import com.androidplot.xy.BoundaryMode;\r
+import com.androidplot.xy.LineAndPointFormatter;\r
+import com.androidplot.xy.LineAndPointRenderer;\r
+import com.androidplot.xy.SimpleXYSeries;\r
+import com.androidplot.xy.ValueMarker;\r
+import com.androidplot.xy.XValueMarker;\r
+import com.androidplot.xy.XYPlot;\r
+\r
+public class SimulationPlotFragment extends Fragment implements OnTouchListener {\r
+\r
+ private final static String TAG = "SimulationPlot";\r
+\r
+ private XYPlot mySimpleXYPlot;\r
+ private SimpleXYSeries mySeries;\r
+ private PointF minXY;\r
+ private PointF maxXY;\r
+ \r
+ private float absMinX;\r
+ private float absMaxX;\r
+ private float minNoError;\r
+ private float maxNoError;\r
+\r
+ private ScaleGestureDetector mScaleDetector;\r
+ private float mScaleFactor = 1.f;\r
+\r
+ @Override\r
+ public void onAttach(Activity activity) {\r
+ super.onAttach(activity);\r
+ Log.d(TAG,"onAttach");\r
+ }\r
+\r
+ @Override\r
+ public void onCreate(Bundle savedInstanceState) {\r
+ Log.d(TAG,"onCreate");\r
+ super.onCreate(savedInstanceState);\r
+ }\r
+\r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ Log.d(TAG,"onCreateView");\r
+ View v = inflater.inflate(R.layout.motor_burn, container, false);\r
+ mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);\r
+ mySimpleXYPlot.setOnTouchListener(this);\r
+ mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());\r
+ // Motor motor = getMotor();\r
+ // init(motor);\r
+ return v;\r
+ }\r
+\r
+ void init( FlightDataBranch data, FlightDataType selectedSeries, List<FlightEvent> eventsToShow ) {\r
+\r
+ mySimpleXYPlot.clear();\r
+ \r
+ if ( data == null || selectedSeries == null || eventsToShow == null ) {\r
+ return;\r
+ }\r
+ \r
+ mySimpleXYPlot.setUserDomainOrigin(0);\r
+ mySimpleXYPlot.setUserRangeOrigin(0);\r
+ mySimpleXYPlot.setRangeLabel("");\r
+ mySimpleXYPlot.setDomainLabel(FlightDataType.TYPE_TIME.getUnitGroup().getDefaultUnit().toString());\r
+ mySimpleXYPlot.setRangeLabel( selectedSeries.getUnitGroup().getDefaultUnit().toString() ); \r
+ mySimpleXYPlot.disableAllMarkup();\r
+\r
+ for ( FlightEvent event : eventsToShow ) {\r
+ XValueMarker xmarker = new XValueMarker( event.getTime(), event.getType().toString() );\r
+ xmarker.setTextOrientation( ValueMarker.TextOrientation.VERTICAL );\r
+ mySimpleXYPlot.addMarker( xmarker );\r
+ }\r
+ \r
+ List<Double> yvals = null;\r
+ List<Double> xvals = null;\r
+ try {\r
+ yvals = data.get(selectedSeries);\r
+ xvals = data.get(FlightDataType.TYPE_TIME);\r
+ Log.d("plot","data = " + yvals);\r
+ } catch ( Exception ex ) {\r
+ Log.d(TAG, "Exception: " + ex);\r
+ }\r
+ if ( yvals == null || yvals.size() == 0 ) {\r
+ yvals = new Vector<Double>();\r
+ yvals.add(0.0);\r
+ yvals.add(0.0);\r
+ yvals.add(1.0);\r
+ yvals.add(1.0);\r
+ }\r
+ Log.d("plot","data = " + yvals.toString());\r
+\r
+ mySeries = new SimpleXYSeries(xvals, yvals, FlightDataType.TYPE_ALTITUDE.toString());\r
+\r
+ mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,\r
+ new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null));\r
+\r
+ //Set of internal variables for keeping track of the boundaries\r
+ mySimpleXYPlot.calculateMinMaxVals();\r
+ \r
+ mySimpleXYPlot.redraw();\r
+\r
+ minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());\r
+ maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());\r
+\r
+ absMinX = minXY.x;\r
+ absMaxX = maxXY.x;\r
+ \r
+ minNoError = Math.round(mySeries.getX(1).floatValue() +2);\r
+ maxNoError = Math.round(mySeries.getX(mySeries.size() -1).floatValue()) - 2.0f;\r
+ }\r
+\r
+ private float mPosX;\r
+ private float mPosY;\r
+\r
+ private float mLastTouchX;\r
+ private float mLastTouchY;\r
+\r
+ private int mActivePointerId = -1;\r
+\r
+ @Override\r
+ public boolean onTouch(View arg0, MotionEvent event) {\r
+ mScaleDetector.onTouchEvent(event);\r
+\r
+ final int action = event.getAction();\r
+ switch ( action & MotionEvent.ACTION_MASK ) {\r
+ case MotionEvent.ACTION_DOWN: {\r
+ final float x = event.getX();\r
+ final float y = event.getY();\r
+\r
+ mLastTouchX = x;\r
+ mLastTouchY = y;\r
+\r
+ mActivePointerId = event.getPointerId(0);\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_MOVE: {\r
+ final int pointerIndex = event.findPointerIndex(mActivePointerId);\r
+ final float x = event.getX(pointerIndex);\r
+ final float y = event.getY(pointerIndex);\r
+\r
+ if (!mScaleDetector.isInProgress()) {\r
+ final float dx = x - mLastTouchX;\r
+ final float dy = y - mLastTouchY;\r
+ \r
+ mPosX += dx;\r
+ mPosY += dy;\r
+ scroll(dx);\r
+ // do scroll.\r
+ \r
+ }\r
+ mLastTouchX = x;\r
+ mLastTouchY = y;\r
+ \r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_UP: {\r
+ mActivePointerId = -1;\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_CANCEL: {\r
+ mActivePointerId = -1;\r
+ break;\r
+ }\r
+ \r
+ case MotionEvent.ACTION_POINTER_UP: {\r
+ final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;\r
+ final int pointerId = event.getPointerId(pointerIndex);\r
+ if (pointerId == mActivePointerId) {\r
+ // This was our active pointer going up. choose a new active pointer and adjust accordingly.\r
+ final int newPointerIndex = pointerIndex ==0 ? 1:0;\r
+ mLastTouchX = event.getX(newPointerIndex);\r
+ mLastTouchY = event.getY(newPointerIndex);\r
+ mActivePointerId = event.getPointerId(newPointerIndex);\r
+ }\r
+ break;\r
+ }\r
+ } \r
+ return true;\r
+ }\r
+\r
+ private void zoom(float scale) {\r
+ Log.d(TAG,"zoom by " + scale);\r
+ float domainSpan = absMaxX - absMinX;\r
+ Log.d(TAG,"domainSpan = " + domainSpan);\r
+ float domainMidPoint = absMaxX - domainSpan / 2.0f;\r
+ Log.d(TAG,"domainMidPoint = " + domainMidPoint);\r
+ float offset = domainSpan / scale;\r
+ Log.d(TAG,"offset " + offset);\r
+ minXY.x=domainMidPoint- offset;\r
+ Log.d(TAG,"min X " + minXY.x);\r
+ maxXY.x=domainMidPoint+offset;\r
+ Log.d(TAG,"max X " + maxXY.x);\r
+ checkBoundaries();\r
+ mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
+ mySimpleXYPlot.redraw();\r
+ }\r
+\r
+ private void scroll(float pan) {\r
+ float domainSpan = maxXY.x - minXY.x;\r
+ float step = domainSpan / mySimpleXYPlot.getWidth();\r
+ float offset = pan * step;\r
+ minXY.x+= offset;\r
+ maxXY.x+= offset;\r
+ checkBoundaries();\r
+ mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
+ mySimpleXYPlot.redraw();\r
+ }\r
+\r
+ private void checkBoundaries() {\r
+ \r
+ if ( minXY.x < absMinX) \r
+ minXY.x = absMinX;\r
+// else if ( minXY.x > maxNoError )\r
+// minXY.x = maxNoError;\r
+ \r
+ if ( maxXY.x > absMaxX)\r
+ maxXY.x = absMaxX;\r
+// else if ( maxXY.x < minNoError)\r
+// maxXY.x = minNoError;\r
+ }\r
+ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {\r
+ @Override\r
+ public boolean onScale( ScaleGestureDetector detector ) {\r
+ mScaleFactor *= detector.getScaleFactor();\r
+\r
+ mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));\r
+ zoom(mScaleFactor);\r
+ return true;\r
+ }\r
+ }\r
+}\r
+\r
--- /dev/null
+package net.sf.openrocket.android.simulation;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.simulation.FlightDataBranch;\r
+import net.sf.openrocket.simulation.FlightDataType;\r
+import net.sf.openrocket.simulation.FlightEvent;\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.util.SparseBooleanArray;\r
+import android.view.LayoutInflater;\r
+import android.view.Menu;\r
+import android.view.MenuInflater;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.ImageView;\r
+import android.widget.ListView;\r
+import android.widget.SlidingDrawer;\r
+import android.widget.TabHost;\r
+import android.widget.TextView;\r
+\r
+public class SimulationViewer 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 ListView eventList;\r
+ private ListView seriesList;\r
+\r
+ private SimulationPlotFragment simPlot;\r
+\r
+ private Simulation sim;\r
+ private FlightDataBranch data;\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.simulation_detail);\r
+\r
+ Intent i = getIntent();\r
+ int simnumber = i.getIntExtra("Simulation", 0);\r
+ sim = ((Application)this.getApplication()).getRocketDocument().getSimulation(simnumber);\r
+ data = sim.getSimulatedData().getBranch(0);\r
+\r
+ simPlot = (SimulationPlotFragment) getSupportFragmentManager().findFragmentById(R.id.simulationPlotFragment);\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
+ TabHost tabs=(TabHost)findViewById(R.id.simulationConfigurationForm);\r
+\r
+ tabs.setup();\r
+\r
+ TabHost.TabSpec spec=tabs.newTabSpec("tag1");\r
+\r
+ spec.setContent(R.id.simulationEventsList);\r
+ spec.setIndicator("Events");\r
+ tabs.addTab(spec);\r
+\r
+ spec=tabs.newTabSpec("tag2");\r
+ spec.setContent(R.id.simulationSeriesList);\r
+ spec.setIndicator("Series");\r
+ tabs.addTab(spec); \r
+\r
+ eventList = (ListView) findViewById(R.id.simulationEventsList);\r
+\r
+ seriesList = (ListView) findViewById(R.id.simulationSeriesList);\r
+\r
+ // Initialize the eventList\r
+ ArrayAdapter<FlightEvent> events = new ArrayAdapter<FlightEvent>(this,android.R.layout.simple_list_item_multiple_choice,data.getEvents()) {\r
+\r
+ @Override\r
+ public View getView(int position, View convertView,\r
+ ViewGroup parent) {\r
+ View v = convertView;\r
+ if ( v == null ) {\r
+ LayoutInflater li = getLayoutInflater();\r
+ v = li.inflate(android.R.layout.simple_list_item_multiple_choice,null);\r
+ }\r
+ FlightEvent event = this.getItem(position);\r
+ ((TextView)v.findViewById(android.R.id.text1)).setText( event.getType().toString() + " " + event.getTime() + " (s)" );\r
+ return v;\r
+ }\r
+\r
+ };\r
+ eventList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);\r
+ eventList.setAdapter(events);\r
+\r
+ List<FlightDataType> selectableSeries = new ArrayList<FlightDataType>();\r
+ for( FlightDataType fdt : data.getTypes() ) {\r
+ if ( fdt == FlightDataType.TYPE_TIME ) { \r
+\r
+ } else {\r
+ selectableSeries.add(fdt);\r
+ }\r
+ }\r
+ ArrayAdapter<FlightDataType> serieses = new ArrayAdapter<FlightDataType>(this,android.R.layout.simple_list_item_multiple_choice,selectableSeries) {\r
+\r
+ @Override\r
+ public View getView(int position, View convertView,\r
+ ViewGroup parent) {\r
+ View v = convertView;\r
+ if ( v == null ) {\r
+ LayoutInflater li = getLayoutInflater();\r
+ v = li.inflate(android.R.layout.simple_list_item_multiple_choice,null);\r
+ }\r
+ FlightDataType fdt = this.getItem(position);\r
+ ((TextView)v.findViewById(android.R.id.text1)).setText( fdt.toString() );\r
+ return v;\r
+ }\r
+\r
+ };\r
+ seriesList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);\r
+ seriesList.setAdapter(serieses);\r
+ redraw();\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
+ redraw();\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
+ private void redraw() {\r
+ List<FlightEvent> eventsToShow = new ArrayList<FlightEvent>();\r
+ {\r
+ SparseBooleanArray eventsSelected = eventList.getCheckedItemPositions();\r
+ List<FlightEvent> flightEvents = data.getEvents();\r
+ for( int i=0; i< flightEvents.size(); i++ ) {\r
+ if ( eventsSelected.get(i) ) {\r
+ eventsToShow.add(flightEvents.get(i) );\r
+ }\r
+ }\r
+ }\r
+ FlightDataType selectedSeries = null;\r
+ {\r
+ int selected = seriesList.getCheckedItemPosition();\r
+ if ( selected >= 0 ) {\r
+ selectedSeries = (FlightDataType) seriesList.getAdapter().getItem(selected);\r
+ }\r
+ }\r
+\r
+ simPlot.init(data, selectedSeries, eventsToShow );\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.IOException;\r
+import java.io.Reader;\r
+import java.io.StringReader;\r
+import java.io.StringWriter;\r
+\r
+public abstract class Base64Decoder {\r
+\r
+ private static final String BASE64_CHARS =\r
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
+ private static final char PAD_CHAR = '=';\r
+\r
+ private final static short[] _charToBits = new short[128];\r
+\r
+ static {\r
+\r
+ for (int i = 0; i < _charToBits.length; i++)\r
+ _charToBits[i] = -1;\r
+\r
+ for (int i = 0; i < BASE64_CHARS.length(); i++)\r
+ _charToBits[BASE64_CHARS.charAt(i)] = (byte) i;\r
+ _charToBits[PAD_CHAR] = 0;\r
+\r
+ }\r
+ \r
+ /**\r
+ * Decode the specified Base64 string and write binary data\r
+ * to the given stream.\r
+ * @param str Base64 encoded string\r
+ * @param w output stream\r
+ */\r
+ public static String decodeData(String str) throws IOException\r
+ {\r
+ StringReader r;\r
+ int c1;\r
+\r
+ if (str == null || str.length() < 1)\r
+ return null;\r
+\r
+ r = new StringReader(str);\r
+ \r
+ StringWriter w = new StringWriter();\r
+\r
+ // spin through the input string\r
+ c1 = readToNonSpace(r);\r
+ while (c1 > 0)\r
+ {\r
+ int c2, c3, c4;\r
+ int p1, p2, p3, p4;\r
+ int pad, n;\r
+\r
+ pad = 0;\r
+\r
+ c2 = readToNonSpace(r);\r
+ c3 = readToNonSpace(r);\r
+ c4 = readToNonSpace(r);\r
+ if (c4 < 0)\r
+ throw new IllegalArgumentException("Encoded string ends prematurely.");\r
+\r
+ p1 = charToBits(c1);\r
+ p2 = charToBits(c2);\r
+\r
+ if (c3 == PAD_CHAR)\r
+ {\r
+ p3 = 0;\r
+ pad++;\r
+ }\r
+ else\r
+ p3 = charToBits(c3);\r
+\r
+ if (c4 == PAD_CHAR)\r
+ {\r
+ p4 = 0;\r
+ pad++;\r
+ }\r
+ else\r
+ p4 = charToBits(c4);\r
+\r
+ if (p1 < 0 || p2 < 0 || p3 < 0 || p4 < 0)\r
+ throw new IllegalArgumentException("Encoded string contains invalid characters.");\r
+\r
+ n = (p1 << 18) | (p2 << 12) | (p3 << 6) | p4;\r
+\r
+ w.write((byte) ((n & 0xFF0000) >> 16));\r
+ if (pad < 2)\r
+ w.write((byte) ((n & 0x00FF00) >> 8));\r
+ if (pad < 1)\r
+ w.write((byte) (n & 0x0000FF));\r
+\r
+ c1 = readToNonSpace(r);\r
+ if (c1 > 0 && pad > 0)\r
+ throw new IllegalArgumentException("Extra characters found after padding.");\r
+ }\r
+ \r
+ return w.toString();\r
+ }\r
+\r
+\r
+ private static int readToNonSpace(Reader r)\r
+ throws IOException\r
+ {\r
+ int c;\r
+\r
+ c = r.read();\r
+ while (c >= 0 && Character.isWhitespace(c))\r
+ c = r.read();\r
+\r
+ return c;\r
+ }\r
+\r
+ private static int charToBits(int c)\r
+ {\r
+ // use it to look up the value\r
+ if (c < 0 || c >= _charToBits.length)\r
+ return -1;\r
+ else\r
+ return _charToBits[c];\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.ArrayList;\r
+\r
+class DownloadRequest {\r
+\r
+ private ArrayList<Integer> motorIds = new ArrayList<Integer>();\r
+ \r
+ private String format = null;\r
+ \r
+ public void add( Integer motorId ) {\r
+ this.motorIds.add(motorId);\r
+ }\r
+ \r
+ public void setFormat( String format ) {\r
+ this.format = format;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ StringBuilder w = new StringBuilder();\r
+ \r
+ w.append("<?xml version=\"1.0\" encoding=\"ascii\"?>\n");\r
+ w.append("<download-request\n");\r
+ w.append(" xmlns=\"http://www.thrustcurve.org/2008/DownloadRequest\"\n");\r
+ w.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");\r
+ w.append(" xsi:schemaLocation=\"http://www.thrustcurve.org/2008/DownloadRequest http://www.thrustcurve.org/2008/download-request.xsd\">\n");\r
+\r
+ if ( format != null ) {\r
+ w.append(" <format>").append(format).append("</format>\n");\r
+ }\r
+ \r
+ w.append(" <motor-ids>\n");\r
+ for( Integer i : motorIds ) {\r
+ w.append(" <id>").append(i).append("</id>\n");\r
+ }\r
+ w.append(" </motor-ids>\n");\r
+ w.append("</download-request>\n");\r
+ return w.toString();\r
+ }\r
+\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+\r
+public class DownloadResponse {\r
+\r
+ private Map<Integer,MotorBurnFile> data = new HashMap<Integer,MotorBurnFile>();\r
+ \r
+ private String error = null;\r
+ \r
+ public void add( MotorBurnFile mbd ) {\r
+ MotorBurnFile currentData = data.get(mbd.getMotorId());\r
+ if ( currentData == null || currentData.getDatapoints().size() < mbd.getDatapoints().size() ) {\r
+ data.put(mbd.getMotorId(),mbd);\r
+ }\r
+ }\r
+\r
+ public MotorBurnFile getData(Integer motor_id) {\r
+ return data.get(motor_id);\r
+ }\r
+ \r
+ public void setError(String error) {\r
+ this.error = error;\r
+ }\r
+ \r
+ public String getError() {\r
+ return error;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ return "DownloadResponse [error=" + error + ", data=" + data + "]";\r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.InputStream;\r
+\r
+import org.xml.sax.Attributes;\r
+\r
+import android.sax.Element;\r
+import android.sax.EndElementListener;\r
+import android.sax.EndTextElementListener;\r
+import android.sax.RootElement;\r
+import android.sax.StartElementListener;\r
+import android.util.Log;\r
+import android.util.Xml;\r
+\r
+public class DownloadResponseParser {\r
+\r
+ private static final String TAG = "DownloadResponseParser";\r
+\r
+ private static final String thrustcurveURI = "http://www.thrustcurve.org/2009/DownloadResponse";\r
+\r
+ private static final String root_tag = "download-response";\r
+ private static final String results_tag = "results";\r
+ private static final String result_tag = "result";\r
+ private static final String motor_id_tag = "motor-id";\r
+ private static final String simfile_id_tag = "simfile-id";\r
+ private static final String format_tag = "format";\r
+ private static final String source_tag = "source";\r
+ private static final String license_tag = "license";\r
+ private static final String data_tag = "data";\r
+ private static final String error_tag = "error";\r
+\r
+ public static DownloadResponse parse( InputStream in ) {\r
+\r
+ final DownloadResponse ret = new DownloadResponse();\r
+ final MotorBurnFile currentMotor = new MotorBurnFile();\r
+\r
+ // Have a place to put the data string and format.\r
+ // We hold on to these here, then push them into the currentMotor\r
+ // only if it a supported filetype\r
+ final StringHolder current_format = new StringHolder();\r
+ final StringHolder current_data = new StringHolder();\r
+\r
+ RootElement rootEl = new RootElement(thrustcurveURI, root_tag);\r
+ /*\r
+ rootEl.setStartElementListener(\r
+ new StartElementListener() {\r
+ public void start(Attributes arg0) {\r
+ Log.d(TAG,"Start Element error");\r
+ ret.setError("IsError");\r
+ }\r
+ }\r
+ );\r
+ */\r
+ Element resultsEl = rootEl.getChild( thrustcurveURI, results_tag);\r
+ Element resultEl = resultsEl.getChild( thrustcurveURI, result_tag);\r
+ resultEl.setStartElementListener(\r
+ new StartElementListener() {\r
+ @Override\r
+ public void start(Attributes arg0) {\r
+ Log.d(TAG,"Start Element result");\r
+ currentMotor.init();\r
+ }\r
+ }\r
+ );\r
+\r
+ resultEl.setEndElementListener(\r
+ new EndElementListener() {\r
+ @Override\r
+ public void end() {\r
+ if ( SupportedFileTypes.isSupportedFileType(current_format.s) ) {\r
+ currentMotor.setFiletype(current_format.s);\r
+ String s = null;\r
+ try {\r
+ s = Base64Decoder.decodeData(current_data.s);\r
+ } catch ( Exception ex ) {\r
+ Log.d(TAG,"base64: " + ex.getMessage());\r
+ }\r
+ currentMotor.decodeFile( s );\r
+ }\r
+ ret.add((MotorBurnFile)currentMotor.clone());\r
+ }\r
+ }\r
+ );\r
+\r
+ resultEl.getChild(thrustcurveURI,motor_id_tag).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setMotor_id(Integer.parseInt(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,format_tag).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ current_format.s = arg0;\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,data_tag).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ current_data.s = arg0;\r
+ }\r
+ }\r
+ );\r
+ try {\r
+ Xml.parse(in, Xml.Encoding.UTF_8, rootEl.getContentHandler());\r
+ } catch (Exception e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+\r
+ return ret;\r
+ }\r
+\r
+ private static class StringHolder {\r
+ public String s;\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.Vector;\r
+\r
+public class MotorBurnFile {\r
+\r
+ private Integer motor_id;\r
+ private String filetype;\r
+ private Float length;\r
+ private String delays;\r
+ private Double propWeightG;\r
+ private Double totWeightG;\r
+ private Vector<Double> datapoints = new Vector<Double>();\r
+ \r
+ public void init() {\r
+ this.motor_id = null;\r
+ this.filetype = null;\r
+ this.length = null;\r
+ this.delays = null;\r
+ this.propWeightG = null;\r
+ this.totWeightG = null;\r
+ this.datapoints = new Vector<Double>();\r
+ }\r
+ \r
+ @Override\r
+ public MotorBurnFile clone() {\r
+ MotorBurnFile clone = new MotorBurnFile();\r
+ clone.motor_id = this.motor_id;\r
+ clone.filetype = this.filetype;\r
+ clone.length = this.length;\r
+ clone.delays = this.delays;\r
+ clone.propWeightG = this.propWeightG;\r
+ clone.totWeightG = this.totWeightG;\r
+ clone.datapoints = this.datapoints;\r
+ return clone;\r
+ }\r
+\r
+ public void decodeFile(String data){\r
+ if (SupportedFileTypes.RASP_FORMAT.equals(filetype)) {\r
+ RaspBurnFile.parse(this,data);\r
+ } else if (SupportedFileTypes.ROCKSIM_FORMAT.equals(filetype) ){\r
+ RSEBurnFile.parse(this,data);\r
+ }\r
+ }\r
+ \r
+ public Integer getMotorId() {\r
+ return motor_id;\r
+ }\r
+ public String getFileType() {\r
+ return filetype;\r
+ }\r
+ public Float getLength() {\r
+ return length;\r
+ }\r
+ public String getDelays() {\r
+ return delays;\r
+ }\r
+ public Double getPropWeightG() {\r
+ return propWeightG;\r
+ }\r
+ public Double getTotWeightG() {\r
+ return totWeightG;\r
+ }\r
+ public Vector<Double> getDatapoints() {\r
+ return datapoints;\r
+ }\r
+\r
+ void setMotor_id(Integer motor_id) {\r
+ this.motor_id = motor_id;\r
+ }\r
+ void setFiletype(String filetype ) {\r
+ this.filetype = filetype;\r
+ }\r
+ void setLength(Float length) {\r
+ this.length = length;\r
+ }\r
+ void setDelays(String delays) {\r
+ this.delays = delays;\r
+ }\r
+ void setPropWeightG(Double propWeightG) {\r
+ this.propWeightG = propWeightG;\r
+ }\r
+ void setTotWeightG(Double totWeightG) {\r
+ this.totWeightG = totWeightG;\r
+ }\r
+ void setDatapoints(Vector<Double> datapoints) {\r
+ this.datapoints = datapoints;\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.InputStream;\r
+import java.util.Vector;\r
+\r
+import org.xml.sax.Attributes;\r
+\r
+import android.sax.Element;\r
+import android.sax.RootElement;\r
+import android.sax.StartElementListener;\r
+import android.util.Log;\r
+import android.util.Xml;\r
+\r
+class RSEBurnFile extends MotorBurnFile {\r
+\r
+ private final static String TAG = "RSEBurnFile";\r
+\r
+ static void parse( MotorBurnFile that, String filecontents ) {\r
+\r
+ parse(that, new ByteArrayInputStream(filecontents.getBytes()) );\r
+ }\r
+\r
+ private final static String root_tag = "engine-database";\r
+ private final static String engine_list_tag = "engine-list";\r
+ private final static String engine_tag = "engine";\r
+\r
+ private final static String delays_attr = "delays";\r
+ private final static String len_attr = "len";\r
+ private final static String propwgt_attr = "propWt";\r
+ private final static String totwgt_attr = "initWt";\r
+\r
+ private final static String data_tag = "data";\r
+ private final static String eng_data_tag = "eng-data";\r
+\r
+ private final static String time_attr="t";\r
+ private final static String force_attr="f";\r
+\r
+ static void parse( final MotorBurnFile that, InputStream in ) {\r
+\r
+ RootElement rootEl = new RootElement(root_tag);\r
+ Element engineEl = rootEl.getChild(engine_list_tag).getChild(engine_tag);\r
+\r
+ final Vector<Double> datapoints = new Vector<Double>();\r
+ \r
+ Log.d(TAG,"parsing start");\r
+\r
+ engineEl.setStartElementListener(\r
+ new StartElementListener() {\r
+ @Override\r
+ public void start(Attributes arg0) {\r
+ Log.d(TAG,"start engineEl");\r
+ that.setPropWeightG(Double.parseDouble(arg0.getValue(propwgt_attr)));\r
+ that.setTotWeightG(Double.parseDouble(arg0.getValue(totwgt_attr)));\r
+ that.setLength(Float.parseFloat(arg0.getValue(len_attr)));\r
+ that.setDelays(arg0.getValue(delays_attr));\r
+ Log.d(TAG, "me is now " + that.toString());\r
+ }\r
+ }\r
+ );\r
+\r
+ Element datapointEl = engineEl.getChild(data_tag).getChild(eng_data_tag);\r
+ datapointEl.setStartElementListener(\r
+ new StartElementListener() {\r
+ @Override\r
+ public void start(Attributes attributes) {\r
+ Double x = Double.parseDouble(attributes.getValue(time_attr));\r
+ Double y = Double.parseDouble(attributes.getValue(force_attr));\r
+ Log.d(TAG, "add data point " + x + "," + y);\r
+ datapoints.add(x);\r
+ datapoints.add(y);\r
+ }\r
+ }\r
+ );\r
+\r
+ try {\r
+ Xml.parse(in, Xml.Encoding.UTF_8, rootEl.getContentHandler());\r
+ } catch (Exception e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+\r
+ that.setDatapoints(datapoints);\r
+ }\r
+}\r
+//\r
+// <engine-database>\r
+// <engine-list>\r
+// <engine FDiv="10" FFix="1" FStep="-1." Isp="202.11" Itot="8.919" Type="single-use" auto-calc-cg="1" auto-calc-mass="1" avgThrust="3.795" burn-time="2.35" cgDiv="10" cgFix="1" cgStep="-1." code="C4" delays="3,5,7" dia="18." exitDia="0." initWt="17." len="50." mDiv="10" mFix="1" mStep="-1." massFrac="26.47" mfg="Apogee" peakThrust="11.31" propWt="4.5" tDiv="10" tFix="1" tStep="-1." throatDia="0.">\r
+// <comments>Apogee C4 RASP.ENG file made from NAR published data\r
+// File produced September 4, 2000\r
+// The total impulse, peak thrust, average thrust and burn time are\r
+// the same as the averaged static test data on the NAR web site in\r
+// the certification file. The curve drawn with these data points is as\r
+// close to the certification curve as can be with such a limited\r
+// number of points (32) allowed with wRASP up to v1.6.\r
+// </comments>\r
+// <data>\r
+// <eng-data cg="25." f="0." m="4.5" t="0."/>\r
+// <eng-data cg="25." f="3.23" m="4.48533" t="0.018"/>\r
+// <eng-data cg="25." f="6.874" m="4.42671" t="0.041"/>\r
+// <eng-data cg="25." f="8.779" m="4.00814" t="0.147"/>\r
+// <eng-data cg="25." f="10.683" m="3.28643" t="0.294"/>\r
+// <eng-data cg="25." f="11.31" m="2.89252" t="0.365"/>\r
+// <eng-data cg="25." f="10.521" m="2.76585" t="0.388"/>\r
+// <eng-data cg="25." f="8.779" m="2.649" t="0.412"/>\r
+// <eng-data cg="25." f="7.04" m="2.53328" t="0.441"/>\r
+// <eng-data cg="25." f="4.555" m="2.46308" t="0.465"/>\r
+// <eng-data cg="25." f="3.479" m="2.33337" t="0.529"/>\r
+// <eng-data cg="25." f="2.981" m="2.1704" t="0.629"/>\r
+// <eng-data cg="25." f="3.23" m="2.1328" t="0.653"/>\r
+// <eng-data cg="25." f="2.816" m="2.03366" t="0.718"/>\r
+// <eng-data cg="25." f="2.733" m="1.84469" t="0.853"/>\r
+// <eng-data cg="25." f="2.65" m="1.5568" t="1.065"/>\r
+// <eng-data cg="25." f="2.567" m="1.30938" t="1.253"/>\r
+// <eng-data cg="25." f="2.401" m="1.05873" t="1.453"/>\r
+// <eng-data cg="25." f="2.484" m="0.761739" t="1.694"/>\r
+// <eng-data cg="25." f="2.484" m="0.636413" t="1.794"/>\r
+// <eng-data cg="25." f="2.733" m="0.612724" t="1.812"/>\r
+// <eng-data cg="25." f="2.401" m="0.575165" t="1.841"/>\r
+// <eng-data cg="25." f="2.401" m="0.446759" t="1.947"/>\r
+// <eng-data cg="25." f="2.401" m="0.246881" t="2.112"/>\r
+// <eng-data cg="25." f="2.401" m="0.0978809" t="2.235"/>\r
+// <eng-data cg="25." f="2.236" m="0.0429024" t="2.282"/>\r
+// <eng-data cg="25." f="1.656" m="0.0134478" t="2.312"/>\r
+// <eng-data cg="25." f="0.662" m="0.003507" t="2.329"/>\r
+// <eng-data cg="25." f="0." m="-0." t="2.35"/>\r
+// </data>\r
+// </engine>\r
+// </engine-list>\r
+// </engine-database>\r
+//\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.IOException;\r
+import java.io.LineNumberReader;\r
+import java.io.StringReader;\r
+import java.util.Vector;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+import android.util.Log;\r
+\r
+\r
+class RaspBurnFile{\r
+\r
+ private final static String TAG = "RaspBurnFile";\r
+ \r
+ private final static int HEADER = 0;\r
+ private final static int DATA = 1;\r
+ private final static Pattern headerPattern = Pattern.compile("(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)");\r
+ private final static Pattern dataPattern = Pattern.compile("(\\S*)\\s+(\\S*)");\r
+ \r
+ static void parse( MotorBurnFile that, String filecontents ) {\r
+ \r
+ int state = HEADER;\r
+ \r
+ LineNumberReader reader = new LineNumberReader( new StringReader(filecontents));\r
+ \r
+ Vector<Double> datapoints = new Vector<Double>();\r
+ \r
+ String line;\r
+ Matcher m;\r
+ try {\r
+ while ( (line = reader.readLine()) != null ) {\r
+ line = line.trim();\r
+ Log.d("RASP",line);\r
+ if ( line.startsWith(";")) {\r
+ continue;\r
+ }\r
+ switch (state) {\r
+ \r
+ case HEADER:\r
+ Log.d("RASP","header");\r
+ m = headerPattern.matcher(line);\r
+ if ( m.matches() ) {\r
+ Log.d("RASP","header matches");\r
+ \r
+ /*motorName = m.group(1);*/\r
+ /*diameter = Integer.decode(m.group(2));*/\r
+ that.setLength(Float.parseFloat(m.group(3)) );\r
+ String delays = m.group(4);\r
+ if ( delays != null ) {\r
+ delays = delays.replace("-", ",");\r
+ that.setDelays(delays);\r
+ }\r
+ that.setPropWeightG(Double.parseDouble(m.group(5))*1000.0);\r
+ that.setTotWeightG(Double.parseDouble(m.group(6))*1000.0);\r
+ /*manufacturer = m.group(7);*/\r
+ \r
+ }\r
+ state = DATA;\r
+ break;\r
+ \r
+ case DATA:\r
+ Log.d("RASP","data");\r
+ m = dataPattern.matcher(line);\r
+ if ( m.matches() ) {\r
+ Log.d("RASP","data matches");\r
+ Double x = Double.parseDouble(m.group(1));\r
+ Double y = Double.parseDouble(m.group(2));\r
+ Log.d("RASP","data matches ("+x+","+y+")");\r
+ datapoints.add(x);\r
+ datapoints.add(y);\r
+ }\r
+ break;\r
+ }\r
+ that.setDatapoints(datapoints);\r
+ }\r
+ } catch (IOException ex ) {\r
+ Log.d(TAG,"Unable to parse Rasp file: " + ex);\r
+ }\r
+ \r
+ }\r
+ \r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+public class SearchRequest {\r
+\r
+ private String manufacturer;\r
+ private String designation;\r
+ private String brand_name;\r
+ \r
+ private String common_name;\r
+ private String impulse_class;\r
+ private Integer diameter;\r
+ \r
+ /*\r
+ public enum Type {\r
+ "SU";\r
+ "reload";\r
+ "hybrid"\r
+ };\r
+ */\r
+ private String type;\r
+ \r
+ public void setManufacturer(String manufacturer) {\r
+ this.manufacturer = null;\r
+ if ( manufacturer != null ) {\r
+ manufacturer = manufacturer.trim();\r
+ if ( ! "".equals(manufacturer) ) {\r
+ this.manufacturer = manufacturer;\r
+ }\r
+ }\r
+ }\r
+\r
+ public void setDesignation(String designation) {\r
+ this.designation = designation;\r
+ }\r
+\r
+ public void setBrand_name(String brand_name) {\r
+ this.brand_name = brand_name;\r
+ }\r
+\r
+ public void setCommon_name(String common_name) {\r
+ if ( common_name == null ) {\r
+ this.common_name = null;\r
+ return;\r
+ }\r
+ this.common_name = common_name.trim();\r
+ if ( "".equals(this.common_name)) {\r
+ this.common_name = null;\r
+ }\r
+ }\r
+\r
+ public void setImpulse_class(String impulse_class) {\r
+ this.impulse_class = null;\r
+ if ( impulse_class != null ) {\r
+ this.impulse_class = impulse_class.trim();\r
+ if ( "".equals(impulse_class) ) {\r
+ this.impulse_class = null;\r
+ }\r
+ }\r
+ }\r
+\r
+ public void setDiameter(Integer diameter) {\r
+ this.diameter = diameter;\r
+ }\r
+ \r
+ public void setDiameter(String diameter) {\r
+ this.diameter = null;\r
+ if ( diameter == null ) {\r
+ return;\r
+ }\r
+ try {\r
+ this.diameter = Integer.decode(diameter);\r
+ } catch ( NumberFormatException ex ) {\r
+ this.diameter = null;\r
+ }\r
+ }\r
+\r
+ public void setType(String type) {\r
+ this.type = type;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ StringBuilder w = new StringBuilder();\r
+ \r
+ w.append("<?xml version=\"1.0\" encoding=\"ascii\"?>\n");\r
+ w.append("<search-request\n");\r
+ w.append(" xmlns=\"http://www.thrustcurve.org/2011/SearchRequest\"\n");\r
+ w.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");\r
+ w.append(" xsi:schemaLocation=\"http://www.thrustcurve.org/2011/SearchRequest http://www.thrustcurve.org/2011/search-request.xsd\">\n");\r
+\r
+ if ( manufacturer != null ) {\r
+ w.append(" <manufacturer>").append(manufacturer).append("</manufacturer>\n");\r
+ }\r
+ if ( designation != null ) {\r
+ w.append(" <designation>").append(designation).append("</designation>\n");\r
+ }\r
+ if ( brand_name != null ) {\r
+ w.append(" <brand-name>").append(brand_name).append("</brand-name>\n");\r
+ }\r
+ if ( common_name != null ) {\r
+ w.append(" <common-name>").append(common_name).append("</common-name>\n");\r
+ }\r
+ if ( impulse_class != null ) {\r
+ w.append(" <impulse-class>").append(impulse_class).append("</impulse-class>\n");\r
+ }\r
+ if ( diameter != null ) {\r
+ w.append(" <diameter>").append(diameter).append("</diameter>\n");\r
+ }\r
+ if ( type != null ) {\r
+ w.append(" <type>").append(type).append("</type>\n");\r
+ }\r
+ w.append("<data-fields>*</data-fields>");\r
+ w.append("<max-results>50</max-results>");\r
+ w.append("</search-request>\n");\r
+ return w.toString();\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+\r
+public class SearchResponse {\r
+\r
+ private List<TCMotor> results = new ArrayList<TCMotor>();\r
+ \r
+ private int matches;\r
+ \r
+ private String error;\r
+\r
+ public List<TCMotor> getResults() {\r
+ return results;\r
+ }\r
+\r
+ public void setResults(List<TCMotor> results) {\r
+ this.results = results;\r
+ }\r
+\r
+ public int getMatches() {\r
+ return matches;\r
+ }\r
+\r
+ public void setMatches(int matches) {\r
+ this.matches = matches;\r
+ }\r
+\r
+ public String getError() {\r
+ return error;\r
+ }\r
+\r
+ public void setError(String error) {\r
+ this.error = error;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "SearchResult [results=" + results + ", matches=" + matches\r
+ + ", error=" + error + "]";\r
+ }\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.InputStream;\r
+\r
+import org.xml.sax.Attributes;\r
+\r
+import android.sax.Element;\r
+import android.sax.EndElementListener;\r
+import android.sax.EndTextElementListener;\r
+import android.sax.RootElement;\r
+import android.sax.StartElementListener;\r
+import android.util.Xml;\r
+\r
+public class SearchResponseParser {\r
+\r
+ private static final String thrustcurveURI = "http://www.thrustcurve.org/2008/SearchResponse";\r
+ /*\r
+ * XML Tags in SearchResult xsd\r
+ */\r
+ private static final String root_tag = "search-response";\r
+ private static final String criteria = "criteria";\r
+ private static final String criterion = "criterion";\r
+ private static final String name = "name";\r
+ private static final String value = "value";\r
+ private static final String matches = "matches";\r
+ private static final String results = "results";\r
+ private static final String result = "result";\r
+ \r
+ private static final String motor_id = "motor-id";\r
+ private static final String manufacturer = "manufacturer";\r
+ private static final String manufacturer_abbr = "manufacturer-abbrev";\r
+ private static final String designation = "designation";\r
+ private static final String brand_name = "brand-name";\r
+ private static final String common_name = "common-name";\r
+ private static final String impulse_class = "impulse-class";\r
+ private static final String diameter = "diameter";\r
+ private static final String length = "length";\r
+ private static final String type = "type";\r
+ private static final String cert_org = "cert-org";\r
+ private static final String avg_thrust_n = "avg-thrust-n";\r
+ private static final String max_thrust_n = "max-thrust-n";\r
+ private static final String tot_impulse_ns = "tot-impulse-ns";\r
+ private static final String burn_time_s = "burn-time-s";\r
+ private static final String data_files = "data-files";\r
+ private static final String info_url = "info-url";\r
+ private static final String total_weight_g = "total-weight-g";\r
+ private static final String prop_weight_g = "prop-weight-g";\r
+ private static final String delays = "delays";\r
+ private static final String case_info = "case-info";\r
+ private static final String prop_info = "prop-info";\r
+ private static final String updated_on = "updated-on";\r
+ \r
+ public static SearchResponse parse( InputStream in ) {\r
+ \r
+ final SearchResponse ret = new SearchResponse();\r
+ final TCMotor currentMotor = new TCMotor();\r
+\r
+ RootElement rootEl = new RootElement(thrustcurveURI, root_tag);\r
+ Element criteriaEl = rootEl.getChild( thrustcurveURI, criteria);\r
+ \r
+ criteriaEl.getChild(thrustcurveURI,matches).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ ret.setMatches(Integer.parseInt(arg0));\r
+ }\r
+ }\r
+ );\r
+ Element resultsEl = rootEl.getChild(thrustcurveURI,results);\r
+ Element resultEl = resultsEl.getChild(thrustcurveURI,result);\r
+\r
+ resultEl.setStartElementListener(\r
+ new StartElementListener() {\r
+ @Override\r
+ public void start(Attributes arg0) {\r
+ currentMotor.init();\r
+ }\r
+ }\r
+ );\r
+ \r
+ resultEl.setEndElementListener(\r
+ new EndElementListener() {\r
+ @Override\r
+ public void end() {\r
+ ret.getResults().add((TCMotor)currentMotor.clone());\r
+ }\r
+ }\r
+ );\r
+ \r
+ resultEl.getChild(thrustcurveURI,motor_id).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setMotor_id(Integer.parseInt(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,manufacturer).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ if ( arg0 != null ) {\r
+ currentMotor.setManufacturer(arg0);\r
+ }\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,manufacturer_abbr).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ if ( arg0 != null ) {\r
+ currentMotor.setManufacturer_abbr(arg0);\r
+ }\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,designation).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setDesignation(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,brand_name).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setBrand_name(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,common_name).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setCommon_name(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,impulse_class).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setImpulse_class(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,diameter).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setDiameter(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,length).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setLength(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,type).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setType(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,cert_org).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setCert_org(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,avg_thrust_n).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setAvg_thrust_n(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,max_thrust_n).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setMax_thrust_n(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,tot_impulse_ns).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setTot_impulse_ns(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,burn_time_s).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setBurn_time_s(Float.parseFloat(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,data_files).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setData_files(Integer.parseInt(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,info_url).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setInfo_url(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,total_weight_g).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setTot_mass_g(Double.parseDouble(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,prop_weight_g).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setProp_mass_g(Double.parseDouble(arg0));\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,delays).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setDelays(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,case_info).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setCase_info(arg0);\r
+ }\r
+ }\r
+ );\r
+ resultEl.getChild(thrustcurveURI,prop_info).setEndTextElementListener(\r
+ new EndTextElementListener() {\r
+ @Override\r
+ public void end(String arg0) {\r
+ currentMotor.setProp_info(arg0);\r
+ }\r
+ }\r
+ );\r
+\r
+\r
+ try {\r
+ Xml.parse(in, Xml.Encoding.UTF_8, rootEl.getContentHandler());\r
+ } catch (Exception e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+\r
+ return ret;\r
+ }\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+public abstract class SupportedFileTypes {\r
+\r
+ public final static String ROCKSIM_FORMAT = "RockSim";\r
+ public final static String RASP_FORMAT = "RASP";\r
+ \r
+ public static boolean isSupportedFileType( String arg0 ) {\r
+ return (ROCKSIM_FORMAT.equals(arg0) || RASP_FORMAT.equals(arg0));\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.Date;\r
+import java.util.Vector;\r
+\r
+public class TCMotor implements Cloneable {\r
+\r
+ private Integer motor_id;\r
+ private String manufacturer;\r
+ private String manufacturer_abbr;\r
+ private String designation;\r
+ private String brand_name;\r
+ private String common_name;\r
+ private String impulse_class;\r
+ private Float diameter;\r
+ private Float length;\r
+ private String type;\r
+ private String cert_org;\r
+ private Float avg_thrust_n;\r
+ private Float max_thrust_n;\r
+ private Float tot_impulse_ns;\r
+ private Float burn_time_s;\r
+ private Integer data_files;\r
+ private String info_url;\r
+ private Double tot_mass_g;\r
+ private Double prop_mass_g;\r
+ private String delays;\r
+ private String case_info;\r
+ private String prop_info;\r
+ private Date updated_on;\r
+ private Vector<Double> burndata;\r
+ \r
+ public void init() {\r
+ motor_id = null;\r
+ manufacturer = null;\r
+ manufacturer_abbr = null;\r
+ designation = null;\r
+ brand_name = null;\r
+ common_name = null;\r
+ impulse_class = null;\r
+ diameter = null;\r
+ length = null;\r
+ type = null;\r
+ cert_org = null;\r
+ avg_thrust_n = null;\r
+ max_thrust_n = null;\r
+ tot_impulse_ns = null;\r
+ burn_time_s = null;\r
+ data_files = null;\r
+ info_url = null;\r
+ tot_mass_g = null;\r
+ prop_mass_g = null;\r
+ delays = null;\r
+ case_info = null;\r
+ prop_info = null;\r
+ updated_on = null;\r
+ burndata = null;\r
+ }\r
+ \r
+ @Override\r
+ public TCMotor clone() {\r
+ TCMotor clone = new TCMotor();\r
+ clone.motor_id = this.motor_id;\r
+ clone.manufacturer = this.manufacturer;\r
+ clone.manufacturer_abbr = this.manufacturer_abbr;\r
+ clone.designation = this.designation;\r
+ clone.brand_name = this.brand_name;\r
+ clone.common_name = this.common_name;\r
+ clone.impulse_class = this.impulse_class;\r
+ clone.diameter = this.diameter;\r
+ clone.length = this.length;\r
+ clone.type = this.type;\r
+ clone.cert_org = this.cert_org;\r
+ clone.avg_thrust_n = this.avg_thrust_n;\r
+ clone.max_thrust_n = this.max_thrust_n;\r
+ clone.tot_impulse_ns = this.tot_impulse_ns;\r
+ clone.burn_time_s = this.burn_time_s;\r
+ clone.data_files = this.data_files;\r
+ clone.info_url = this.info_url;\r
+ clone.tot_mass_g = this.tot_mass_g;\r
+ clone.prop_mass_g = this.prop_mass_g;\r
+ clone.delays = this.delays;\r
+ clone.case_info = this.case_info;\r
+ clone.prop_info = this.prop_info;\r
+ clone.updated_on = this.updated_on;\r
+ clone.burndata = this.burndata;\r
+ return clone;\r
+ }\r
+\r
+ public Integer getMotor_id() {\r
+ return motor_id;\r
+ }\r
+\r
+ public void setMotor_id(Integer motor_id) {\r
+ this.motor_id = motor_id;\r
+ }\r
+\r
+ public String getManufacturer() {\r
+ return manufacturer;\r
+ }\r
+\r
+ public void setManufacturer(String manufacturer) {\r
+ this.manufacturer = manufacturer;\r
+ }\r
+\r
+ public String getManufacturer_abbr() {\r
+ return manufacturer_abbr;\r
+ }\r
+\r
+ public void setManufacturer_abbr(String manufacturer_abbr) {\r
+ this.manufacturer_abbr = manufacturer_abbr;\r
+ }\r
+\r
+ public String getDesignation() {\r
+ return designation;\r
+ }\r
+\r
+ public void setDesignation(String designation) {\r
+ this.designation = designation;\r
+ }\r
+\r
+ public String getBrand_name() {\r
+ return brand_name;\r
+ }\r
+\r
+ public void setBrand_name(String brand_name) {\r
+ this.brand_name = brand_name;\r
+ }\r
+\r
+ public String getCommon_name() {\r
+ return common_name;\r
+ }\r
+\r
+ public void setCommon_name(String common_name) {\r
+ this.common_name = common_name;\r
+ }\r
+\r
+ public String getImpulse_class() {\r
+ return impulse_class;\r
+ }\r
+\r
+ public void setImpulse_class(String impulse_class) {\r
+ this.impulse_class = impulse_class;\r
+ }\r
+\r
+ public Float getDiameter() {\r
+ return diameter;\r
+ }\r
+\r
+ public void setDiameter(Float diameter) {\r
+ this.diameter = diameter;\r
+ }\r
+\r
+ public Float getLength() {\r
+ return length;\r
+ }\r
+\r
+ public void setLength(Float length) {\r
+ this.length = length;\r
+ }\r
+\r
+ public String getType() {\r
+ return type;\r
+ }\r
+\r
+ public void setType(String type) {\r
+ this.type = type;\r
+ }\r
+\r
+ public String getCert_org() {\r
+ return cert_org;\r
+ }\r
+\r
+ public void setCert_org(String cert_org) {\r
+ this.cert_org = cert_org;\r
+ }\r
+\r
+ public Float getAvg_thrust_n() {\r
+ return avg_thrust_n;\r
+ }\r
+\r
+ public void setAvg_thrust_n(Float avg_thrust_n) {\r
+ this.avg_thrust_n = avg_thrust_n;\r
+ }\r
+\r
+ public Float getMax_thrust_n() {\r
+ return max_thrust_n;\r
+ }\r
+\r
+ public void setMax_thrust_n(Float max_thrust_n) {\r
+ this.max_thrust_n = max_thrust_n;\r
+ }\r
+\r
+ public Float getTot_impulse_ns() {\r
+ return tot_impulse_ns;\r
+ }\r
+\r
+ public void setTot_impulse_ns(Float tot_impulse_ns) {\r
+ this.tot_impulse_ns = tot_impulse_ns;\r
+ }\r
+\r
+ public Float getBurn_time_s() {\r
+ return burn_time_s;\r
+ }\r
+\r
+ public void setBurn_time_s(Float burn_time_s) {\r
+ this.burn_time_s = burn_time_s;\r
+ }\r
+\r
+ public Integer getData_files() {\r
+ return data_files;\r
+ }\r
+\r
+ public void setData_files(Integer data_files) {\r
+ this.data_files = data_files;\r
+ }\r
+\r
+ public String getInfo_url() {\r
+ return info_url;\r
+ }\r
+\r
+ public void setInfo_url(String info_url) {\r
+ this.info_url = info_url;\r
+ }\r
+\r
+ public Double getTot_mass_g() {\r
+ return tot_mass_g;\r
+ }\r
+\r
+ public void setTot_mass_g(Double tot_mass_g) {\r
+ this.tot_mass_g = tot_mass_g;\r
+ }\r
+\r
+ public Double getProp_mass_g() {\r
+ return prop_mass_g;\r
+ }\r
+\r
+ public void setProp_mass_g(Double prop_mass_g) {\r
+ this.prop_mass_g = prop_mass_g;\r
+ }\r
+\r
+ public String getDelays() {\r
+ return delays;\r
+ }\r
+\r
+ public void setDelays(String delays) {\r
+ this.delays = delays;\r
+ }\r
+\r
+ public String getCase_info() {\r
+ return case_info;\r
+ }\r
+\r
+ public void setCase_info(String case_info) {\r
+ this.case_info = case_info;\r
+ }\r
+\r
+ public String getProp_info() {\r
+ return prop_info;\r
+ }\r
+\r
+ public void setProp_info(String prop_info) {\r
+ this.prop_info = prop_info;\r
+ }\r
+\r
+ public Date getUpdated_on() {\r
+ return updated_on;\r
+ }\r
+\r
+ public void setUpdated_on(Date updated_on) {\r
+ this.updated_on = updated_on;\r
+ }\r
+\r
+ public Vector<Double> getBurndata() {\r
+ return burndata;\r
+ }\r
+\r
+ public void setBurndata(Vector<Double> burndata) {\r
+ this.burndata = burndata;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "TCMotor [motor_id=" + motor_id + ", manufacturer="\r
+ + manufacturer + ", manufacturer_abbr=" + manufacturer_abbr\r
+ + ", designation=" + designation + ", brand_name=" + brand_name\r
+ + ", common_name=" + common_name + ", impulse_class="\r
+ + impulse_class + ", diameter=" + diameter + ", length="\r
+ + length + ", type=" + type + ", cert_org=" + cert_org\r
+ + ", avg_thrust_n=" + avg_thrust_n + ", max_thrust_n="\r
+ + max_thrust_n + ", tot_impulse_ns=" + tot_impulse_ns\r
+ + ", burn_time_s=" + burn_time_s + ", data_files=" + data_files\r
+ + ", info_url=" + info_url + ", tot_mass_g=" + tot_mass_g\r
+ + ", prop_mass_g=" + prop_mass_g + ", delays=" + delays\r
+ + ", case_info=" + case_info + ", prop_info=" + prop_info\r
+ + ", updated_on=" + updated_on + "]";\r
+ }\r
+ \r
+}\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.util.Vector;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.DbAdapter;\r
+import net.sf.openrocket.android.motor.Motor;\r
+import android.app.Activity;\r
+import android.app.AlertDialog;\r
+import android.app.ProgressDialog;\r
+import android.content.DialogInterface;\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.util.Log;\r
+import android.view.View;\r
+import android.widget.Button;\r
+import android.widget.EditText;\r
+import android.widget.Spinner;\r
+\r
+public class TCQueryActivity extends Activity {\r
+\r
+ private static final String TAG = "ThrustCurveQueryActivity";\r
+\r
+ private DbAdapter mDbHelper;\r
+\r
+ private ProgressDialog progress;\r
+ private Thread downloadThread;\r
+ private Handler handler;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ setContentView(R.layout.tcqueryform);\r
+\r
+ mDbHelper = new DbAdapter(this);\r
+ mDbHelper.open();\r
+\r
+ final Spinner manufacturerField = (Spinner) findViewById(R.id.TCMotorSearchFormManufacturerField);\r
+ final Spinner impulseField = (Spinner) findViewById(R.id.TCMotorSearchFormImpulseField);\r
+ final Spinner diameterField = (Spinner) findViewById(R.id.TCMotorSearchFormDiameterField);\r
+ final EditText commonNameField = (EditText) findViewById(R.id.TCMotorSearchFormCommonNameField);\r
+\r
+ Button submitButton = (Button) findViewById(R.id.TCMotorSearchFromSubmitButton);\r
+ submitButton.setOnClickListener(\r
+ new View.OnClickListener() {\r
+ @Override\r
+ public void onClick( View v ) {\r
+ Log.d(TAG,"submit button clicked");\r
+\r
+ String commonName = commonNameField.getText().toString();\r
+\r
+ SearchRequest r = new SearchRequest();\r
+ if ( manufacturerField.getSelectedItemPosition() != 0) {\r
+ String m = (String) manufacturerField.getSelectedItem();\r
+ Log.d(TAG,"manufacturer = " + m);\r
+ r.setManufacturer(m);\r
+ }\r
+ if ( impulseField.getSelectedItemPosition() != 0 ) {\r
+ String impulse = (String) impulseField.getSelectedItem();\r
+ Log.d(TAG,"impulse = " + impulse);\r
+ r.setImpulse_class(impulse);\r
+ }\r
+ if ( diameterField.getSelectedItemPosition() != 0 ) {\r
+ String diameter = (String)diameterField.getSelectedItem();\r
+ Log.d(TAG,"diameter = " + diameter);\r
+ r.setDiameter(diameter);\r
+ }\r
+ r.setCommon_name(commonName);\r
+\r
+ Downloader d = new Downloader(r);\r
+\r
+ handler = new Handler();\r
+ progress = ProgressDialog.show(TCQueryActivity.this, null, "");\r
+\r
+ downloadThread = new Thread( d );\r
+ downloadThread.start();\r
+ }\r
+ }\r
+ );\r
+ }\r
+\r
+ @Override\r
+ public Object onRetainNonConfigurationInstance() {\r
+ return downloadThread;\r
+ }\r
+\r
+ @Override\r
+ protected void onDestroy() {\r
+ mDbHelper.close();\r
+ if ( progress != null ) {\r
+ if ( progress.isShowing() ) {\r
+ progress.dismiss();\r
+ }\r
+ progress = null;\r
+ }\r
+ super.onDestroy();\r
+ }\r
+\r
+ private class UpdateMessage implements Runnable {\r
+ private String newMessage;\r
+ UpdateMessage( String message ) {\r
+ this.newMessage = message;\r
+ }\r
+ @Override\r
+ public void run() {\r
+ progress.setMessage(newMessage);\r
+ }\r
+ }\r
+\r
+ private class Dismiss implements Runnable {\r
+ @Override\r
+ public void run() {\r
+ progress.dismiss();\r
+ TCQueryActivity.this.finish();\r
+ }\r
+ }\r
+\r
+ private class Error implements Runnable {\r
+ private String newMessage;\r
+ Error( String message ) {\r
+ this.newMessage = message;\r
+ }\r
+ @Override\r
+ public void run() {\r
+ progress.dismiss();\r
+ final AlertDialog dialog = new AlertDialog.Builder(TCQueryActivity.this).create();\r
+ dialog.setMessage(newMessage);\r
+ dialog.setButton(DialogInterface.BUTTON_NEUTRAL,"Dismiss", new DialogInterface.OnClickListener() {\r
+\r
+ @Override\r
+ public void onClick(DialogInterface arg0, int arg1) {\r
+ dialog.dismiss();\r
+ }\r
+\r
+ });\r
+ dialog.show();\r
+ }\r
+ }\r
+ private class Downloader implements Runnable {\r
+\r
+ SearchRequest request;\r
+\r
+ Downloader( SearchRequest request ) {\r
+ this.request = request;\r
+ }\r
+\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ handler.post( new UpdateMessage("Quering Thrustcurve"));\r
+ SearchResponse res = new ThrustCurveAPI().doSearch(request);\r
+\r
+ int total = res.getResults().size();\r
+ int count = 1;\r
+ for( TCMotor mi : res.getResults() ) {\r
+ handler.post(new UpdateMessage("Downloading details " + count + " of " + total));\r
+ count++;\r
+ if ( mi.getData_files() == null || mi.getData_files().intValue() == 0 ) {\r
+ continue;\r
+ }\r
+\r
+ MotorBurnFile b = new ThrustCurveAPI().downloadData(mi.getMotor_id());\r
+\r
+ if ( b != null ) {\r
+ if ( b.getLength() != null ) {\r
+ mi.setLength( b.getLength() );\r
+ }\r
+ if ( b.getPropWeightG() != null ) {\r
+ mi.setProp_mass_g(b.getPropWeightG());\r
+ }\r
+ if ( b.getTotWeightG() != null ) {\r
+ mi.setTot_mass_g(b.getTotWeightG());\r
+ }\r
+ if ( b.getDelays() != null ) {\r
+ mi.setDelays(b.getDelays());\r
+ }\r
+ mi.setBurndata(b.getDatapoints());\r
+ }\r
+ Log.d(TAG, mi.toString());\r
+\r
+ // convert to Motors. One per delay.\r
+ Motor m = new Motor();\r
+ // Base name of motor.\r
+ String name = mi.getCommon_name() + "-";\r
+\r
+ m.setManufacturer(mi.getManufacturer_abbr());\r
+ // Convert impulse class. ThrustCurve puts mmx, 1/4a and 1/2a as A.\r
+ m.setImpulseClass(mi.getImpulse_class());\r
+ if ( "a".equalsIgnoreCase(mi.getImpulse_class())) {\r
+ if( mi.getCommon_name().startsWith("1/2A") ) {\r
+ m.setImpulseClass("1/2A");\r
+ } else if (mi.getCommon_name().startsWith("1/4A") ) {\r
+ m.setImpulseClass("1/4A");\r
+ } else if (mi.getCommon_name().startsWith("Micro") ) {\r
+ m.setImpulseClass("1/8A");\r
+ }\r
+ }\r
+ m.setAvgThrust(mi.getAvg_thrust_n());\r
+ m.setBurndata(mi.getBurndata());\r
+ m.setBurnTime(mi.getBurn_time_s());\r
+ m.setDiameter(mi.getDiameter() == null ? null : mi.getDiameter().longValue());\r
+ m.setLength(mi.getLength());\r
+ m.setMaxThrust(mi.getMax_thrust_n());\r
+ m.setPropMass(mi.getProp_mass_g());\r
+ m.setTotalImpulse(mi.getTot_impulse_ns());\r
+ m.setTotMass(mi.getTot_mass_g());\r
+ // Convert Case Info.\r
+ if ( mi.getCase_info() == null\r
+ || "single use".equalsIgnoreCase(mi.getCase_info())\r
+ || "single-use".equalsIgnoreCase(mi.getCase_info())) {\r
+ m.setCaseInfo(mi.getType()+ " " + mi.getDiameter() + "x" + mi.getLength());\r
+ } else {\r
+ m.setCaseInfo(mi.getCase_info());\r
+ }\r
+\r
+ Vector<String> delays = new Vector<String>();\r
+ {\r
+ String delaysString = mi.getDelays();\r
+ if ( delaysString != null ) {\r
+ delaysString = delaysString.trim();\r
+ }\r
+\r
+ if ( delaysString == null || "".equals(delaysString)) {\r
+ delays.add("");\r
+ } else {\r
+ String[] delayString = delaysString.split(",");\r
+ for( String d : delayString ) {\r
+ delays.add( d.trim() );\r
+ }\r
+ }\r
+ }\r
+\r
+ for( String d: delays ) {\r
+ if ( "100".equals(d) ) {\r
+ m.setName(name + "P");\r
+ } else {\r
+ m.setName(name + d);\r
+ }\r
+ mDbHelper.getMotorDao().insertOrUpdateMotor(m);\r
+ }\r
+ }\r
+ if ( total < res.getMatches() ) {\r
+ handler.post( new Error( total + " motors downloaded, " + res.getMatches() + " matched. Try restricting the query more.") );\r
+ } else {\r
+ handler.post( new Dismiss());\r
+ }\r
+ }\r
+ catch( Exception ex){\r
+ Log.d(TAG,ex.toString());\r
+ handler.post( new Error(ex.toString()) );\r
+ }\r
+\r
+ }\r
+ }\r
+}\r
+\r
--- /dev/null
+package net.sf.openrocket.android.thrustcurve;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.net.URLConnection;\r
+\r
+import android.util.Log;\r
+\r
+\r
+public class ThrustCurveAPI {\r
+\r
+ private final static String TAG = "ThrustCurveAPI";\r
+ \r
+ private String url_base = "http://www.thrustcurve.org/servlets/";\r
+ \r
+ public SearchResponse doSearch( SearchRequest request ) throws MalformedURLException, IOException {\r
+ \r
+ String requestString = request.toString();\r
+ \r
+ Log.d(TAG, "doSearch: " + requestString);\r
+ URL url = new URL(url_base + "search");\r
+\r
+ OutputStream stream;\r
+\r
+ URLConnection conn = url.openConnection();\r
+ conn.setConnectTimeout(2000);\r
+ conn.setDoInput(true);\r
+ conn.setDoOutput(true);\r
+ conn.setUseCaches(false);\r
+\r
+ stream = conn.getOutputStream();\r
+\r
+ stream.write(requestString.getBytes());\r
+ \r
+ InputStream is = conn.getInputStream();\r
+\r
+ SearchResponse result = SearchResponseParser.parse(is);\r
+ Log.d(TAG,result.toString());\r
+ \r
+ return result;\r
+ }\r
+\r
+ public MotorBurnFile downloadData( Integer motor_id ) throws MalformedURLException, IOException {\r
+\r
+ if ( motor_id == null ) {\r
+ return null;\r
+ }\r
+ DownloadRequest dr = new DownloadRequest();\r
+ dr.add(motor_id);\r
+\r
+ String requestString = dr.toString();\r
+\r
+ Log.d(TAG, "downloadData: " + requestString);\r
+ URL url = new URL(url_base + "download");\r
+\r
+ OutputStream stream;\r
+\r
+ URLConnection conn = url.openConnection();\r
+ conn.setDoInput(true);\r
+ conn.setDoOutput(true);\r
+ conn.setUseCaches(false);\r
+\r
+ stream = conn.getOutputStream();\r
+\r
+ stream.write(requestString.getBytes());\r
+\r
+ InputStream is = conn.getInputStream();\r
+\r
+ DownloadResponse downloadResponse = DownloadResponseParser.parse(is);\r
+ Log.d(TAG,downloadResponse.toString());\r
+\r
+ MotorBurnFile mbf = downloadResponse.getData(motor_id);\r
+\r
+ return mbf;\r
+\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.database;\r
+\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.motor.Motor;\r
+\r
+public interface MotorDatabase {\r
+\r
+ /**\r
+ * Return all motors in the database matching a search criteria. Any search criteria that\r
+ * is null or NaN is ignored.\r
+ * \r
+ * @param type the motor type, or null.\r
+ * @param manufacturer the manufacturer, or null.\r
+ * @param designation the designation, or null.\r
+ * @param diameter the diameter, or NaN.\r
+ * @param length the length, or NaN.\r
+ * @return a list of all the matching motors.\r
+ */\r
+ public List<? extends Motor> findMotors(Motor.Type type,\r
+ String manufacturer, String designation, double diameter,\r
+ double length);\r
+\r
+}
\ No newline at end of file
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.MathUtil;
-public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
+class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
// Comparators:
private static final Collator COLLATOR = Collator.getInstance(Locale.US);
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
-public abstract class ThrustCurveMotorSetDatabase {
+public abstract class ThrustCurveMotorSetDatabase implements MotorDatabase {
private static final LogHelper logger = Application.getLogger();
}
- /**
- * Return a list of the ThrustCurveMotorSet objects. The list is in sorted order and
- * is unmodifiable.
- *
- * @return the list of all ThrustCurveMotorSets.
+ /* (non-Javadoc)
+ * @see net.sf.openrocket.database.ThrustCurveMotorSetDatabaseI#getMotorSets()
*/
public List<ThrustCurveMotorSet> getMotorSets() {
blockUntilLoaded();
- /**
- * Return all motors in the database matching a search criteria. Any search criteria that
- * is null or NaN is ignored.
- *
- * @param type the motor type, or null.
- * @param manufacturer the manufacturer, or null.
- * @param designation the designation, or null.
- * @param diameter the diameter, or NaN.
- * @param length the length, or NaN.
- * @return a list of all the matching motors.
+ /* (non-Javadoc)
+ * @see net.sf.openrocket.database.ThrustCurveMotorSetDatabaseI#findMotors(net.sf.openrocket.motor.Motor.Type, java.lang.String, java.lang.String, double, double)
*/
+ @Override
public List<ThrustCurveMotor> findMotors(Motor.Type type, String manufacturer, String designation,
double diameter, double length) {
blockUntilLoaded();
return null;
}
- List<ThrustCurveMotor> motors = Application.getMotorSetDatabase().findMotors(type, manufacturer,
+ List<? extends Motor> motors = Application.getMotorSetDatabase().findMotors(type, manufacturer,
designation, diameter, length);
// No motors
// One motor
if (motors.size() == 1) {
- ThrustCurveMotor m = motors.get(0);
+ Motor m = motors.get(0);
if (digest != null && !MotorDigest.digestMotor(m).equals(digest)) {
String str = "Motor with designation '" + designation + "'";
if (manufacturer != null)
if (digest != null) {
// Check for motor with correct digest
- for (ThrustCurveMotor m : motors) {
+ for (Motor m : motors) {
if (MotorDigest.digestMotor(m).equals(digest)) {
return m;
}
// No digest, check for preferred digest (OpenRocket <= 1.1.0)
// TODO: MEDIUM: This should only be done for document versions 1.1 and below
- for (ThrustCurveMotor m : motors) {
+ for (Motor m : motors) {
if (PreferredMotorDigests.DIGESTS.contains(MotorDigest.digestMotor(m))) {
return m;
}
public double getMaxThrustEstimate();
public double getTotalImpulseEstimate();
+ public double[] getTimePoints();
+ public double[] getThrustPoints();
+ public Coordinate[] getCGPoints();
}
* @param m the motor to digest
* @return the digest
*/
- public static String digestMotor(ThrustCurveMotor m) {
+ public static String digestMotor(Motor m) {
// Create the motor digest from data available in RASP files
MotorDigest motorDigest = new MotorDigest();
package net.sf.openrocket.motor;
+import java.io.Serializable;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
package net.sf.openrocket.startup;
-import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
+import net.sf.openrocket.database.MotorDatabase;
import net.sf.openrocket.l10n.ClassBasedTranslator;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.ExceptionSuppressingTranslator;
private static Translator baseTranslator = new DebugTranslator(null);
- private static ThrustCurveMotorSetDatabase motorSetDatabase;
+ private static MotorDatabase motorSetDatabase;
private static Preferences preferences;
/**
* Return the database of all thrust curves loaded into the system.
*/
- public static ThrustCurveMotorSetDatabase getMotorSetDatabase() {
+ public static MotorDatabase getMotorSetDatabase() {
return motorSetDatabase;
}
/**
* Set the database of thrust curves loaded into the system.
*/
- public static void setMotorSetDatabase(ThrustCurveMotorSetDatabase motorSetDatabase) {
+ public static void setMotorSetDatabase(MotorDatabase motorSetDatabase) {
Application.motorSetDatabase = motorSetDatabase;
}