updates
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Tue, 9 Jun 2009 16:56:52 +0000 (16:56 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Tue, 9 Jun 2009 16:56:52 +0000 (16:56 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@7 180e2498-e6e9-4542-8430-84ac67f01cd8

33 files changed:
ChangeLog
build.properties [new file with mode: 0644]
build.xml
dists/OpenRocket-0.9.0.jar [new file with mode: 0644]
html/contact.html
html/documentation.html
html/download.html
html/features.html
html/index.html
html/license.html
html/report.html
html/screenshots.html
src/net/sf/openrocket/document/OpenRocketDocument.java
src/net/sf/openrocket/document/Simulation.java
src/net/sf/openrocket/document/events/DocumentChangeEvent.java [new file with mode: 0644]
src/net/sf/openrocket/document/events/DocumentChangeListener.java [new file with mode: 0644]
src/net/sf/openrocket/document/events/SimulationChangeEvent.java [new file with mode: 0644]
src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java
src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
src/net/sf/openrocket/gui/dialogs/BugDialog.java
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/gui/main/ClipboardListener.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/DocumentSelectionModel.java
src/net/sf/openrocket/gui/main/OpenRocketClipboard.java
src/net/sf/openrocket/gui/main/RocketActions.java
src/net/sf/openrocket/gui/main/SimulationPanel.java
src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
src/net/sf/openrocket/rocketcomponent/Configuration.java
src/net/sf/openrocket/rocketcomponent/Rocket.java
src/net/sf/openrocket/simulation/SimulationConditions.java
src/net/sf/openrocket/startup/Startup.java
src/net/sf/openrocket/util/Icons.java
src/net/sf/openrocket/util/Prefs.java

index 7efec8a2494b76b47cad3edc92a788251f370f1e..9808b616db4909f1d823aa9fe5fd5830d9feb7e9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-06-08  Sampo Niskanen
+
+       * Fixed loading of icons from JAR
+
+2009-06-06  Sampo Niskanen
+
+       * Cut/Copy/Paste of simulations
+       * Improved build scripts
+
 2009-05-28  Sampo Niskanen
 
        * Added startup check for Java 1.6 and OpenJDK
diff --git a/build.properties b/build.properties
new file mode 100644 (file)
index 0000000..d7a601e
--- /dev/null
@@ -0,0 +1,8 @@
+
+# The OpenRocket build version
+build.version=0.9.1pre
+
+# The source of the package.  When building a package for a specific
+# distribution (Debian, Fedora etc.), this should be changed appropriately!
+build.source=default
+
index c4892fa8bc3cb950f7b89e684467bd1a2eb15b51..939d54b1f99f51714962b1984f9595162105b179 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -1,18 +1,25 @@
 <project name="OpenRocket" basedir=".">
 
+       <property file="build.properties" />
+       
        <property name="src.dir"     value="src"/>                      <!-- Source directory -->
        <property name="build.dir"   value="build"/>            <!-- Build directory -->
        
        <!-- Distribution directory, from which stuff is jar'ed -->
        <property name="dist.dir"    value="${build.dir}/dist"/> 
+       <property name="test.dir"    value="${build.dir}/test"/>
        
        <property name="classes.dir" value="${dist.dir}"/>      <!-- Directory for classes -->
        <property name="jar.dir"     value="${build.dir}/jar"/> <!-- Directory for built jar's -->
        <property name="lib.dir"     value="lib"/>                              <!-- Library source directory -->
 
+       <property name="jar.file"    value="${jar.dir}/${ant.project.name}.jar"/>
+       <property name="dist.bin"    value="${jar.dir}/${ant.project.name}-${build.version}.jar"/>
+       <property name="dist.src"    value="${jar.dir}/${ant.project.name}-src-${build.version}.zip"/>
        
        <!-- The main class of the application -->
        <property name="main-class"  value="net.sf.openrocket.startup.Startup"/>
+       <property name="main-dir" value="net/sf/openrocket/startup"/>
 
        
        <!-- Classpath definition -->
        </path>
        
        
+       
+       
        <!-- CLEAN -->
        <target name="clean">
                <delete dir="${build.dir}"/>
        </target>
                
+       
        <!-- BUILD -->
        <target name="build">
                <mkdir dir="${classes.dir}"/>
-               <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
+               <echo>Compiling main classes</echo>
+               <javac srcdir="${src.dir}" destdir="${classes.dir}" excludes="${main-dir}/*" classpathref="classpath"/>
+               <echo>Compiling startup classes</echo>
+               <javac srcdir="${src.dir}/${main-dir}" destdir="${classes.dir}" source="1.4" classpathref="classpath"/>
        </target>
        
+       
        <!-- JAR -->
        <target name="jar" depends="build">
                <copy todir="${dist.dir}/">
-                       <fileset dir="." includes="LICENSE.TXT" />
-                       <fileset dir="." includes="README.TXT" />
-                       <fileset dir="." includes="datafiles/**/* pix/**/*" />
+                       <fileset dir="." includes="LICENSE.TXT README.TXT build.properties" />
+                       <fileset dir="." includes="datafiles/ pix/" />
                </copy>
                <mkdir dir="${jar.dir}"/>
-               <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${dist.dir}">
+               <jar destfile="${jar.file}" basedir="${dist.dir}">
                        <manifest>
                                <attribute name="Main-Class" value="${main-class}"/>
                                <attribute name="SplashScreen-Image" value="pix/splashscreen.png"/>
                </jar>
        </target>
        
-       <!-- RUN -->
-       <target name="run" depends="jar">
-               <java fork="true" classname="${main-class}">
-                       <classpath>
-                               <path location="${jar.dir}/${ant.project.name}.jar"/>
-                       </classpath>
-               </java>
+       
+       <!-- DIST-SRC -->
+       <target name="dist-src" depends="clean">
+               <echo>                  
+               Building source distribution
+               </echo>
+               <mkdir dir="${jar.dir}"/>
+               <zip destfile="${dist.src}">
+                       <!-- Base directory: -->
+                       <fileset dir="." includes="*">
+                               <type type="file"/>
+                       </fileset>
+                       <fileset dir="." includes="datafiles/ lib/ pix/ src/"/>
+               </zip>
+       </target>
+       
+       
+       <!-- DIST-SRC-TEST -->
+       <target name="dist-src-test" depends="dist-src">
+               <echo>
+               Testing source distribution
+               </echo>
+               <delete dir="${test.dir}"/>
+               <mkdir dir="${test.dir}"/>
+               <unzip dest="${test.dir}" src="${dist.src}"/>
+               <ant dir="${test.dir}" antfile="build.xml" target="jar"/>
+               <delete dir="${test.dir}"/>
+               <echo>
+               Test successful
+               </echo>
+       </target>       
+       
+       
+       <!-- DIST-BIN -->
+       <target name="dist-bin" depends="clean,jar">
+               <move file="${jar.file}" tofile="${dist.bin}"/>
        </target>
 
+       
+       <!-- DIST -->
+       <target name="dist" depends="dist-bin,dist-src,dist-src-test">
+               <echo>Distribution ${build.version} (${build.source}) built into directory ${jar.dir}</echo>
+       </target>
+       
 </project>
\ No newline at end of file
diff --git a/dists/OpenRocket-0.9.0.jar b/dists/OpenRocket-0.9.0.jar
new file mode 100644 (file)
index 0000000..7e53618
Binary files /dev/null and b/dists/OpenRocket-0.9.0.jar differ
index f15204306731858d3402704f3c492a541e6f0e0f..73be76d77975d57c6d81f3f2ff0b65c4628b3965 100644 (file)
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index a11e8cec1c3bfd6e080880c10d3e446554d70c0e..d278a7695e659b7bc8e297e594c288b7494889c3 100644 (file)
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index f79600f31a520f3cef0dbb07d548eaa661382c13..1b77a46d18589d95dd58a130220b627516bf7c39 100644 (file)
@@ -56,7 +56,7 @@
     later.  The Sun JRE is recommended.</em></p>
 
     <p class="download">
-    <a href="https://sourceforge.net/project/downloading.php?group_id=260357&filename=OpenRocket-0.9.0.jar">Download OpenRocket 0.9.0</a></p>
+    <a href="https://sourceforge.net/project/downloading.php?group_id=260357&amp;filename=OpenRocket-0.9.0.jar">Download OpenRocket 0.9.0</a></p>
 
     <p>OpenRocket is still considered <strong>beta software</strong>.
     If you encounter any problems, please 
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index 19f48a9e0745684277aaf1549fb5ed2ba2208640..92bd16c7e758248ab59c24e01770e6d862d55e7a 100644 (file)
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index 996320457e245b68ba06a2b7bb420d0b38250bb2..11043688374f569779ede3cb3f71a2085d3d0e13 100644 (file)
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index a7cc999726f9ade08100bb502bf6be17ba7a2fb7..9066611ad2b3227ea067cffba3dd9bd87ac43d4b 100644 (file)
@@ -764,6 +764,19 @@ Public License instead of this License.  But first, please read
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index 9ef2250a0ff5598f29ea166e7c1decad24d1e5f7..1e5be1dc2fc71b416da3d250d068a06e3b9feabb 100644 (file)
@@ -55,9 +55,9 @@
     <ul>
       <li>Search the bug repository to see if the bug has already been
       reported.  If it is, please add extra information to that bug
-      report:<br/>
+      report:
       <form action="https://sourceforge.net/search/index.php" method="get">
-        <input type="hidden" name="group_id" value="260357" />
+        <p><input type="hidden" name="group_id" value="260357" />
        <input type="hidden" name="type_of_search" value="artifact"/>
 <!--    <input type="hidden" name="group_artifact_id" value="1127606" /> -->
 <!--    <input type="hidden" name="artifact_group" value="Bug" /> -->
         <input type="hidden" name="search_comments" value="1" />
 
        <input type="text" name="all_words" value="" />
-       <input type="submit" name="form_submit" value="Search" />
+       <input type="submit" name="form_submit" value="Search" /></p>
       </form>
       </li>
 
       <li>Report the bug using the 
-      <a href="https://sourceforge.net/tracker/?func=add&group_id=260357&atid=1127606">bug
+      <a href="https://sourceforge.net/tracker/?func=add&amp;group_id=260357&amp;atid=1127606">bug
       tracker</a>.  Follow the instructions provided to fill in the 
       report.</li>
 
@@ -97,8 +97,8 @@
     <ul>
       <li>Check that the feature is not already in the
       <a href="features.html#future">planned future features</a> or
-      the <a href="https://sourceforge.net/tracker/?group_id=260357&atid=1127606&artgroup=899287">enhancement requests</a>.</li>
-      <li>Send the request to the <a href="https://sourceforge.net/tracker/?func=add&group_id=260357&atid=1127606">bug tracker</a> as an
+      the <a href="https://sourceforge.net/tracker/?group_id=260357&amp;atid=1127606&amp;artgroup=899287">enhancement requests</a>.</li>
+      <li>Send the request to the <a href="https://sourceforge.net/tracker/?func=add&amp;group_id=260357&amp;atid=1127606">bug tracker</a> as an
       enhancement request.  Please send multiple enhancements as
       individual items.</li>
     </ul>
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index f7e26bc09d6af2984ff6d4c11b593b8441fa6afc..d424922a8f0856bfb800a5d4063e627c347810eb 100644 (file)
     </p>
   </div>
 
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = pkBaseURL + "piwik.php";
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+</script>
+<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+
 </body>
 </html>
 
index ae6c886c833c081c7cbbb3fa22de321bbadea171..24c144cdfb755ad4ec791541689eecfa2ec34cdb 100644 (file)
@@ -10,6 +10,9 @@ import java.util.List;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 
+import net.sf.openrocket.document.events.DocumentChangeEvent;
+import net.sf.openrocket.document.events.DocumentChangeListener;
+import net.sf.openrocket.document.events.SimulationChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.Configuration;
@@ -29,6 +32,8 @@ public class OpenRocketDocument implements ComponentChangeListener {
        public static final int UNDO_MARGIN = 10;
 
        
+       public static final String SIMULATION_NAME_PREFIX = "Simulation ";
+       
        private final Rocket rocket;
        private final Configuration configuration;
 
@@ -48,6 +53,9 @@ public class OpenRocketDocument implements ComponentChangeListener {
        private final StorageOptions storageOptions = new StorageOptions();
        
        
+       private final List<DocumentChangeListener> listeners = 
+               new ArrayList<DocumentChangeListener>();
+       
        /* These must be initialized after undo history is set up. */
        private final UndoRedoAction undoAction;
        private final UndoRedoAction redoAction;
@@ -70,8 +78,6 @@ public class OpenRocketDocument implements ComponentChangeListener {
                redoAction = new UndoRedoAction(UndoRedoAction.REDO);
                
                rocket.addComponentChangeListener(this);
-               
-               
        }
        
        
@@ -135,17 +141,43 @@ public class OpenRocketDocument implements ComponentChangeListener {
        }
        public void addSimulation(Simulation simulation) {
                simulations.add(simulation);
+               fireDocumentChangeEvent(new SimulationChangeEvent(simulation));
        }
        public void addSimulation(Simulation simulation, int n) {
                simulations.add(n, simulation);
+               fireDocumentChangeEvent(new SimulationChangeEvent(simulation));
        }
        public void removeSimulation(Simulation simulation) {
                simulations.remove(simulation);
+               fireDocumentChangeEvent(new SimulationChangeEvent(simulation));
        }
        public Simulation removeSimulation(int n) {
-               return simulations.remove(n);
+               Simulation simulation = simulations.remove(n);
+               fireDocumentChangeEvent(new SimulationChangeEvent(simulation));
+               return simulation;
        }
        
+       /**
+        * Return a unique name suitable for the next simulation.  The name begins
+        * with {@link #SIMULATION_NAME_PREFIX} and has a unique number larger than any
+        * previous simulation.
+        * 
+        * @return      the new name.
+        */
+       public String getNextSimulationName() {
+               // Generate unique name for the simulation
+               int maxValue = 0;
+               for (Simulation s: simulations) {
+                       String name = s.getName();
+                       if (name.startsWith(SIMULATION_NAME_PREFIX)) {
+                               try {
+                                       maxValue = Math.max(maxValue, 
+                                                       Integer.parseInt(name.substring(SIMULATION_NAME_PREFIX.length())));
+                               } catch (NumberFormatException ignore) { }
+                       }
+               }
+               return SIMULATION_NAME_PREFIX + (maxValue+1);
+       }
        
        
        /**
@@ -301,6 +333,24 @@ public class OpenRocketDocument implements ComponentChangeListener {
        
        
        
+       ///////  Listeners
+       
+       public void addDocumentChangeListener(DocumentChangeListener listener) {
+               listeners.add(listener);
+       }
+       
+       public void removeDocumentChangeListener(DocumentChangeListener listener) {
+               listeners.remove(listener);
+       }
+       
+       protected void fireDocumentChangeEvent(DocumentChangeEvent event) {
+               DocumentChangeListener[] array = listeners.toArray(new DocumentChangeListener[0]);
+               for (DocumentChangeListener l: array) {
+                       l.documentChanged(event);
+               }
+       }
+       
+       
        
        
        /**
index 4c4cf2cfd46f1573aa396303f2cb87eeba7ad6fa..5e8d8e9f960d5dff70c094116d7d759b6d0f324d 100644 (file)
@@ -21,7 +21,7 @@ import net.sf.openrocket.simulation.exception.SimulationListenerException;
 import net.sf.openrocket.util.ChangeSource;
 
 
-public class Simulation implements ChangeSource {
+public class Simulation implements ChangeSource, Cloneable {
        
        public static enum Status {
                /** Up-to-date */
@@ -48,9 +48,9 @@ public class Simulation implements ChangeSource {
        private Status status = Status.NOT_SIMULATED;
        
        /** The conditions to use */
-       private final SimulationConditions conditions;
+       private SimulationConditions conditions;
        
-       private List<String> simulationListeners = new ArrayList<String>();
+       private ArrayList<String> simulationListeners = new ArrayList<String>();
        
        private Class<? extends FlightSimulator> simulatorClass = RK4Simulator.class;
        private Class<? extends AerodynamicCalculator> calculatorClass = BarrowmanCalculator.class;
@@ -58,7 +58,7 @@ public class Simulation implements ChangeSource {
        
        
        /** Listeners for this object */
-       private final List<ChangeListener> listeners = new ArrayList<ChangeListener>();
+       private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
        
        
        /** The conditions actually used in the previous simulation, or null */
@@ -304,7 +304,7 @@ public class Simulation implements ChangeSource {
         * 
         * @return      a description of the motor configuration of the previous simulation, or
         *                      <code>null</code>.
-        * @see         Rocket#getMotorConfigurationDescription(String)
+        * @see         Rocket#getMotorConfigurationNameOrDescription(String)
         */
        public String getSimulatedMotorDescription() {
                return simulatedMotors;
@@ -321,7 +321,56 @@ public class Simulation implements ChangeSource {
        }
        
        
+       
+       /**
+        * Returns a copy of this simulation suitable for cut/copy/paste operations.  
+        * This excludes any simulated data.
+        *  
+        * @return      a copy of this simulation and its conditions.
+        */
+       @SuppressWarnings("unchecked")
+       public Simulation copy() {
+               try {
+
+                       Simulation copy = (Simulation)super.clone();
+
+                       copy.status = Status.NOT_SIMULATED;
+                       copy.conditions = this.conditions.clone();
+                       copy.simulationListeners = (ArrayList<String>) this.simulationListeners.clone();
+                       copy.listeners = new ArrayList<ChangeListener>();
+                       copy.simulatedConditions = null;
+                       copy.simulatedMotors = null;
+                       copy.simulatedData = null;
+                       copy.simulatedRocketID = -1;
+
+                       return copy;
+
+               
+               } catch (CloneNotSupportedException e) {
+                       throw new RuntimeException("Clone not supported, BUG", e);
+               }
+       }
+       
+       
+       /**
+        * Create a duplicate of this simulation with the specified rocket.  The new
+        * simulation is in non-simulated state.
+        * 
+        * @param newRocket             the rocket for the new simulation.
+        * @return                              a new simulation with the same conditions and properties.
+        */
+       @SuppressWarnings("unchecked")
+       public Simulation duplicateSimulation(Rocket newRocket) {
+               Simulation copy = new Simulation(newRocket);
+               
+               copy.name = this.name;
+               copy.conditions.copyFrom(this.conditions);
+               copy.simulationListeners = (ArrayList<String>) this.simulationListeners.clone();
+               copy.simulatorClass = this.simulatorClass;
+               copy.calculatorClass = this.calculatorClass;
 
+               return copy;
+       }
        
        
 
diff --git a/src/net/sf/openrocket/document/events/DocumentChangeEvent.java b/src/net/sf/openrocket/document/events/DocumentChangeEvent.java
new file mode 100644 (file)
index 0000000..22ffe94
--- /dev/null
@@ -0,0 +1,11 @@
+package net.sf.openrocket.document.events;
+
+import javax.swing.event.ChangeEvent;
+
+public class DocumentChangeEvent extends ChangeEvent {
+
+       public DocumentChangeEvent(Object source) {
+               super(source);
+       }
+
+}
diff --git a/src/net/sf/openrocket/document/events/DocumentChangeListener.java b/src/net/sf/openrocket/document/events/DocumentChangeListener.java
new file mode 100644 (file)
index 0000000..01d3dbd
--- /dev/null
@@ -0,0 +1,7 @@
+package net.sf.openrocket.document.events;
+
+public interface DocumentChangeListener {
+
+       public void documentChanged(DocumentChangeEvent event);
+       
+}
diff --git a/src/net/sf/openrocket/document/events/SimulationChangeEvent.java b/src/net/sf/openrocket/document/events/SimulationChangeEvent.java
new file mode 100644 (file)
index 0000000..56ed6d1
--- /dev/null
@@ -0,0 +1,10 @@
+package net.sf.openrocket.document.events;
+
+
+public class SimulationChangeEvent extends DocumentChangeEvent {
+
+       public SimulationChangeEvent(Object source) {
+               super(source);
+       }
+
+}
index 9f96997c637268d4fced6b015def952b4fd206fe..b24d0c94168e698612ee4c1e1ee048813ca8a36d 100644 (file)
@@ -181,7 +181,7 @@ public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
                
                @Override
                public String toString() {
-                       return rocket.getMotorConfigurationDescription(id);
+                       return rocket.getMotorConfigurationNameOrDescription(id);
                }
        }
        
@@ -219,7 +219,7 @@ public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
                        columnList.add(new Column("Name") {
                                @Override
                                public Object getValueAt(int row) {
-                                       return rocket.getMotorConfigurationDescription(ids[row]);
+                                       return rocket.getMotorConfigurationNameOrDescription(ids[row]);
                                }
                        });
                        
index 1b2f12ad3dbd6cc4516f4ba31c58926effa949ae..dedd09eadbb3c0c25b29af38cf787aea21173646 100644 (file)
@@ -16,8 +16,10 @@ import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.DescriptionArea;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
 import net.sf.openrocket.rocketcomponent.RingComponent;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.unit.UnitGroup;
@@ -142,8 +144,17 @@ public class RingComponentConfig extends RocketComponentConfig {
 
                
                //// Material
-               panel.add(materialPanel(new JPanel(new MigLayout()), Material.Type.BULK),
-                               "cell 4 0, gapleft paragraph, aligny 0%, spany");
+               JPanel sub = materialPanel(new JPanel(new MigLayout()), Material.Type.BULK);
+               
+               if (component instanceof EngineBlock) {
+                       DescriptionArea desc = new DescriptionArea(6,-1);
+                       desc.setText("<html>An engine block stops the motor from moving forwards in " +
+                                       "the motor mount tube.<br><br>In order to add a motor, create a body tube " +
+                                       "or inner tube and mark it as a motor mount in the <em>Motor</em> " +
+                                       "tab.");
+                       sub.add(desc, "growx");
+               }
+               panel.add(sub,"cell 4 0, gapleft paragraph, aligny 0%, spany");
                
                return panel;
        }
index ae0bee8cc4eafb0e143319e7f22c0aad7a13d390..729bb67b54e8381c4489daf92844fc4e38050bc5 100644 (file)
@@ -41,6 +41,7 @@ public class BugDialog extends JDialog {
                sb.append('\n');
                sb.append("---------- Included system information ----------\n");
                sb.append("OpenRocket version: " + Prefs.getVersion() + "\n");
+               sb.append("OpenRocket source: " + Prefs.getBuildSource() + "\n");
                sb.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n");
                sb.append("System properties:\n");
 
index a924db6489a9aefe9841aaab13a24efbfe16f023..3f12d259fc916fdd7047bd662a52acfce6a54a9c 100644 (file)
@@ -34,6 +34,7 @@ import javax.swing.JSeparator;
 import javax.swing.JSplitPane;
 import javax.swing.JTabbedPane;
 import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
 import javax.swing.LookAndFeel;
 import javax.swing.ScrollPaneConstants;
 import javax.swing.SwingUtilities;
@@ -96,6 +97,10 @@ public class BasicFrame extends JFrame {
     };
     
     
+    
+    public static final int COMPONENT_TAB = 0;
+    public static final int SIMULATION_TAB = 1;
+    
 
        /**
         * List of currently open frames.  When the list goes empty
@@ -118,10 +123,13 @@ public class BasicFrame extends JFrame {
        private final OpenRocketDocument document;
        private final Rocket rocket;
        
+       private JTabbedPane tabbedPane;
        private RocketPanel rocketpanel;
        private ComponentTree tree = null;
+       
+       private final DocumentSelectionModel selectionModel;
        private final TreeSelectionModel componentSelectionModel;
-       // private final ListSelectionModel simulationSelectionModel; ...
+       private final ListSelectionModel simulationSelectionModel;
        
        /** Actions available for rocket modifications */
        private final RocketActions actions;
@@ -150,11 +158,21 @@ public class BasicFrame extends JFrame {
                });
                
                
-               // Create the selection model that will be used
+               // Create the component tree selection model that will be used
                componentSelectionModel = new DefaultTreeSelectionModel();
                componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
                
-               actions = new RocketActions(document, componentSelectionModel, this);
+               // Obtain the simulation selection model that will be used
+               SimulationPanel simulationPanel = new SimulationPanel(document);
+               simulationSelectionModel = simulationPanel.getSimulationListSelectionModel();
+               
+               // Combine into a DocumentSelectionModel
+               selectionModel = new DocumentSelectionModel(document);
+               selectionModel.attachComponentTreeSelectionModel(componentSelectionModel);
+               selectionModel.attachSimulationListSelectionModel(simulationSelectionModel);
+               
+               
+               actions = new RocketActions(document, selectionModel, this);
                
                
                // The main vertical split pane         
@@ -164,11 +182,11 @@ public class BasicFrame extends JFrame {
 
                
                // The top tabbed pane
-               JTabbedPane tabbed = new JTabbedPane();
-               tabbed.addTab("Rocket design", null, designTab());
-               tabbed.addTab("Flight simulations", null, simulationsTab());
+               tabbedPane = new JTabbedPane();
+               tabbedPane.addTab("Rocket design", null, designTab());
+               tabbedPane.addTab("Flight simulations", null, simulationPanel);
                
-               vertical.setTopComponent(tabbed);
+               vertical.setTopComponent(tabbedPane);
                
 
 
@@ -334,15 +352,6 @@ public class BasicFrame extends JFrame {
        }
        
        
-       /**
-        * Construct the "Flight simulations" tab.
-        * @return
-        */
-       private JComponent simulationsTab() {
-               return new SimulationPanel(document);
-       }
-       
-       
        
        /**
         * Creates the menu for the window.
@@ -553,6 +562,16 @@ public class BasicFrame extends JFrame {
        
        
        
+       /**
+        * Select the tab on the main pane.
+        * 
+        * @param tab   one of {@link #COMPONENT_TAB} or {@link #SIMULATION_TAB}.
+        */
+       public void selectTab(int tab) {
+               tabbedPane.setSelectedIndex(tab);
+       }
+
+       
        
        private void openAction() {
            JFileChooser chooser = new JFileChooser();
diff --git a/src/net/sf/openrocket/gui/main/ClipboardListener.java b/src/net/sf/openrocket/gui/main/ClipboardListener.java
new file mode 100644 (file)
index 0000000..87fd445
--- /dev/null
@@ -0,0 +1,7 @@
+package net.sf.openrocket.gui.main;
+
+public interface ClipboardListener {
+
+       public void clipboardChanged();
+       
+}
index 94bc39dfbaedc3ee9671c5dafc0fa5ed63e2c741..746a2341fd9c43a1372816a913941988bf1c3fe9 100644 (file)
@@ -55,6 +55,19 @@ public class DocumentSelectionModel {
        public Simulation[] getSelectedSimulations() {
                return Arrays.copyOf(simulationSelection, simulationSelection.length);
        }
+       
+       public void setSelectedSimulations(Simulation[] sims) {
+               simulationSelection = sims;
+               clearComponentSelection();
+
+               simulationListSelectionModel.clearSelection();
+               for (Simulation s: sims) {
+                       int index = document.getSimulationIndex(s);
+                       if (index >= 0) {
+                               simulationListSelectionModel.addSelectionInterval(index, index);
+                       }
+               }
+       }
 
        /**
         * Return the currently selected rocket component.  Returns <code>null</code>
@@ -65,6 +78,14 @@ public class DocumentSelectionModel {
        public RocketComponent getSelectedComponent() {
                return componentSelection;
        }
+       
+       public void setSelectedComponent(RocketComponent component) {
+               componentSelection = component;
+               clearSimulationSelection();
+       
+               TreePath path = ComponentTreeModel.makeTreePath(component);
+               componentTreeSelectionModel.setSelectionPath(path);
+       }
 
 
 
index b50bffc8560d25335be0d7f40b635d6f1527a232..5541efb0c1127b50ca4adf49ecf581c89f3eb462 100644 (file)
@@ -1,11 +1,17 @@
 package net.sf.openrocket.gui.main;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 
-public class OpenRocketClipboard {
+public final class OpenRocketClipboard {
 
-       private static Object clipboard = null;
+       private static RocketComponent clipboardComponent = null;
+       private static Simulation[] clipboardSimulations = null;
+       
+       private static List<ClipboardListener> listeners = new ArrayList<ClipboardListener>();
        
        private OpenRocketClipboard() {
                // Disallow instantiation
@@ -14,22 +20,51 @@ public class OpenRocketClipboard {
        
        /**
         * Return the <code>RocketComponent</code> contained in the clipboard, or
-        * <code>null</code>.
+        * <code>null</code>.  The component is returned verbatim, and must be copied
+        * before attaching to any rocket design!
         * 
         * @return      the rocket component contained in the clipboard, or <code>null</code>
         *                      if the clipboard does not currently contain a rocket component.
         */
-       public static RocketComponent getComponent() {
-               if (clipboard instanceof RocketComponent) {
-                       return (RocketComponent) clipboard;
-               }
-               return null;
+       public static RocketComponent getClipboardComponent() {
+               return clipboardComponent;
+       }
+       
+       
+       public static void setClipboard(RocketComponent component) {
+               clipboardComponent = component;
+               clipboardSimulations = null;
+               fireClipboardChanged();
+       }
+       
+       
+       public static Simulation[] getClipboardSimulations() {
+               if (clipboardSimulations == null || clipboardSimulations.length == 0)
+                       return null;
+               return clipboardSimulations.clone();
+       }
+       
+       public static void setClipboard(Simulation[] simulations) {
+               clipboardSimulations = simulations.clone();
+               clipboardComponent = null;
+               fireClipboardChanged();
        }
        
        
-       public static Simulation[] getSimulations() {
-               return null; // TODO
+       
+       public static void addClipboardListener(ClipboardListener listener) {
+               listeners.add(listener);
        }
        
+       public static void removeClipboardListener(ClipboardListener listener) {
+               listeners.remove(listener);
+       }
+       
+       private static void fireClipboardChanged() {
+               ClipboardListener[] array = listeners.toArray(new ClipboardListener[0]);
+               for (ClipboardListener l: array) {
+                       l.clipboardChanged();
+               }
+       }
        
 }
index b035228330a71aab3dbb62969aea43823ee65442..5958e18c2b293babfb65e53ac1482fe2a02d48ce 100644 (file)
@@ -4,18 +4,18 @@ package net.sf.openrocket.gui.main;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
-import java.util.List;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
-import javax.swing.JFrame;
+import javax.swing.JCheckBox;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
 import javax.swing.KeyStroke;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
 
+import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
@@ -24,6 +24,7 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
 import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Pair;
+import net.sf.openrocket.util.Prefs;
 
 
 
@@ -35,15 +36,21 @@ import net.sf.openrocket.util.Pair;
  */
 public class RocketActions {
 
-       private static RocketComponent clipboard = null;
-       private static List<RocketAction> clipboardListeners = new ArrayList<RocketAction>();
-
+       public static final KeyStroke CUT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_X,
+                       ActionEvent.CTRL_MASK);
+       public static final KeyStroke COPY_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C,
+                       ActionEvent.CTRL_MASK);
+       public static final KeyStroke PASTE_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_V,
+                       ActionEvent.CTRL_MASK);
+       
        private final OpenRocketDocument document;
        private final Rocket rocket;
-       private final JFrame parentFrame;
-       private final TreeSelectionModel selectionModel;
+       private final BasicFrame parentFrame;
+       private final DocumentSelectionModel selectionModel;
 
 
+       private final RocketAction deleteComponentAction;
+       private final RocketAction deleteSimulationAction;
        private final RocketAction deleteAction;
        private final RocketAction cutAction;
        private final RocketAction copyAction;
@@ -54,8 +61,8 @@ public class RocketActions {
        private final RocketAction moveDownAction;
        
 
-       public RocketActions(OpenRocketDocument document, TreeSelectionModel selectionModel,
-                       JFrame parentFrame) {
+       public RocketActions(OpenRocketDocument document, DocumentSelectionModel selectionModel,
+                       BasicFrame parentFrame) {
                this.document = document;
                this.rocket = document.getRocket();
                this.selectionModel = selectionModel;
@@ -63,6 +70,8 @@ public class RocketActions {
 
                // Add action also to updateActions()
                this.deleteAction = new DeleteAction();
+               this.deleteComponentAction = new DeleteComponentAction();
+               this.deleteSimulationAction = new DeleteSimulationAction();
                this.cutAction = new CutAction();
                this.copyAction = new CopyAction();
                this.pasteAction = new PasteAction();
@@ -71,13 +80,14 @@ public class RocketActions {
                this.moveUpAction = new MoveUpAction();
                this.moveDownAction = new MoveDownAction();
 
+               OpenRocketClipboard.addClipboardListener(this.pasteAction);
                updateActions();
 
                // Update all actions when tree selection or rocket changes
 
-               selectionModel.addTreeSelectionListener(new TreeSelectionListener() {
+               selectionModel.addDocumentSelectionListener(new DocumentSelectionListener() {
                        @Override
-                       public void valueChanged(TreeSelectionEvent e) {
+                       public void valueChanged(int changeType) {
                                updateActions();
                        }
                });
@@ -93,28 +103,26 @@ public class RocketActions {
         * Update the state of all of the actions.
         */
        private void updateActions() {
-               deleteAction.update();
-               cutAction.update();
-               copyAction.update();
-               pasteAction.update();
-               editAction.update();
-               newStageAction.update();
-               moveUpAction.update();
-               moveDownAction.update();
+               deleteAction.clipboardChanged();
+               cutAction.clipboardChanged();
+               copyAction.clipboardChanged();
+               pasteAction.clipboardChanged();
+               editAction.clipboardChanged();
+               newStageAction.clipboardChanged();
+               moveUpAction.clipboardChanged();
+               moveDownAction.clipboardChanged();
        }
        
        
-       /**
-        * Update the state of all actions that depend on the clipboard.
-        */
-       private void updateClipboardActions() {
-               RocketAction[] array = clipboardListeners.toArray(new RocketAction[0]);
-               for (RocketAction a: array) {
-                       a.update();
-               }
+       
+
+       public Action getDeleteComponentAction() {
+               return deleteAction;
        }
 
-       
+       public Action getDeleteSimulationAction() {
+               return deleteAction;
+       }
 
        public Action getDeleteAction() {
                return deleteAction;
@@ -152,30 +160,6 @@ public class RocketActions {
        
        ////////  Helper methods for the actions
 
-       /**
-        * Return the currently selected rocket component, or null if none selected.
-        * 
-        * @return      the currently selected component.
-        */
-       private RocketComponent getSelectedComponent() {
-               RocketComponent c = null;
-               TreePath p = selectionModel.getSelectionPath();
-               if (p != null)
-                       c = (RocketComponent) p.getLastPathComponent();
-
-               if (c != null && c.getRocket() != rocket) {
-                       throw new IllegalStateException("Selection not same as document rocket, "
-                                       + "report bug!");
-               }
-               return c;
-       }
-       
-       private void setSelectedComponent(RocketComponent component) {
-               TreePath path = ComponentTreeModel.makeTreePath(component);
-               selectionModel.setSelectionPath(path);
-       }
-
-
        private boolean isDeletable(RocketComponent c) {
                // Sanity check
                if (c == null || c.getParent() == null)
@@ -195,7 +179,8 @@ public class RocketActions {
 
        private void delete(RocketComponent c) {
                if (!isDeletable(c)) {
-                       throw new IllegalArgumentException("Report bug!  Component " + c + " not deletable.");
+                       throw new IllegalArgumentException("Report bug!  Component " + c + 
+                                       " not deletable.");
                }
 
                RocketComponent parent = c.getParent();
@@ -211,6 +196,42 @@ public class RocketActions {
        }
 
        
+       private boolean isSimulationSelected() {
+               Simulation[] selection = selectionModel.getSelectedSimulations();
+               return (selection != null  &&  selection.length > 0);
+       }
+       
+       
+       
+       private boolean verifyDeleteSimulation() {
+               boolean verify = Prefs.NODE.getBoolean(Prefs.CONFIRM_DELETE_SIMULATION, true);
+               if (verify) {
+                       JPanel panel = new JPanel(new MigLayout());
+                       JCheckBox dontAsk = new JCheckBox("Do not ask me again");
+                       panel.add(dontAsk,"wrap");
+                       panel.add(new ResizeLabel("You can change the default operation in the " +
+                                       "preferences.",-2));
+
+                       int ret = JOptionPane.showConfirmDialog(
+                                       parentFrame,
+                                       new Object[] {
+                                       "Delete the selected simulations?",
+                                       "<html><i>This operation cannot be undone.</i>",
+                                       "",
+                                       panel },
+                                       "Delete simulations",
+                                       JOptionPane.OK_CANCEL_OPTION,
+                                       JOptionPane.WARNING_MESSAGE);
+                       if (ret != JOptionPane.OK_OPTION)
+                               return false;
+
+                       if (dontAsk.isSelected()) {
+                               Prefs.NODE.putBoolean(Prefs.CONFIRM_DELETE_SIMULATION, false);
+                       }
+               }
+
+               return true;
+       }
 
 
        /**
@@ -218,10 +239,11 @@ public class RocketActions {
         * should be pasted.  Returns null if the clipboard is empty or if the
         * clipboard cannot be pasted to the current selection.
         * 
+        * @param   clipboard   the component on the clipboard.
         * @return  a Pair with both components defined, or null.
         */
-       private Pair<RocketComponent, Integer> getPastePosition() {
-               RocketComponent selected = getSelectedComponent();
+       private Pair<RocketComponent, Integer> getPastePosition(RocketComponent clipboard) {
+               RocketComponent selected = selectionModel.getSelectedComponent();
                if (selected == null)
                        return null;
 
@@ -246,39 +268,105 @@ public class RocketActions {
 
        ///////  Action classes
 
-       private abstract class RocketAction extends AbstractAction {
-               public abstract void update();
+       private abstract class RocketAction extends AbstractAction implements ClipboardListener {
+               public abstract void clipboardChanged();
+       }
+
+
+       /**
+        * Action that deletes the selected component.
+        */
+       private class DeleteComponentAction extends RocketAction {
+               public DeleteComponentAction() {
+                       this.putValue(NAME, "Delete");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component.");
+                       this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
+//                     this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
+                       this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
+                       clipboardChanged();
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       RocketComponent c = selectionModel.getSelectedComponent();
+
+                       if (isDeletable(c)) {
+                               ComponentConfigDialog.hideDialog();
+
+                               document.addUndoPosition("Delete " + c.getComponentName());
+                               delete(c);
+                       }
+               }
+
+               @Override
+               public void clipboardChanged() {
+                       this.setEnabled(isDeletable(selectionModel.getSelectedComponent()));
+               }
+       }
+
+
+       
+       /**
+        * Action that deletes the selected component.
+        */
+       private class DeleteSimulationAction extends RocketAction {
+               public DeleteSimulationAction() {
+                       this.putValue(NAME, "Delete");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected simulation.");
+                       this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
+//                     this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
+                       this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
+                       clipboardChanged();
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+                       if (sims.length > 0) {
+                               if (verifyDeleteSimulation()) {
+                                       for (Simulation s: sims) {
+                                               document.removeSimulation(s);
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public void clipboardChanged() {
+                       this.setEnabled(isSimulationSelected());
+               }
        }
 
 
+       
        /**
         * Action that deletes the selected component.
         */
        private class DeleteAction extends RocketAction {
                public DeleteAction() {
                        this.putValue(NAME, "Delete");
-                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component and subcomponents.");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component or simulation.");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
                        this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
                        this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isDeletable(c))
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       document.addUndoPosition("Delete " + c.getComponentName());
-                       delete(c);
+                       if (isSimulationSelected()) {
+                               deleteSimulationAction.actionPerformed(e);
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       } else {
+                               deleteComponentAction.actionPerformed(e);
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(isDeletable(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(isDeletable(selectionModel.getSelectedComponent()) ||
+                                       isSimulationSelected());
                }
        }
 
@@ -291,32 +379,44 @@ public class RocketActions {
                public CutAction() {
                        this.putValue(NAME, "Cut");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_T);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X,
-                                       ActionEvent.CTRL_MASK));
-                       this.putValue(SHORT_DESCRIPTION, "Cut this component (and subcomponents) to "
+                       this.putValue(ACCELERATOR_KEY, CUT_KEY_STROKE);
+                       this.putValue(SHORT_DESCRIPTION, "Cut this component or simulation to "
                                        + "the clipboard and remove from this design");
                        this.putValue(SMALL_ICON, Icons.EDIT_CUT);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isDeletable(c) || !isCopyable(c))
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       document.addUndoPosition("Cut " + c.getComponentName());
-                       clipboard = c.copy();
-                       delete(c);
-                       updateClipboardActions();
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+
+                       if (isDeletable(c) && isCopyable(c)) {
+                               ComponentConfigDialog.hideDialog();
+                               
+                               document.addUndoPosition("Cut " + c.getComponentName());
+                               OpenRocketClipboard.setClipboard(c.copy());
+                               delete(c);
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       } else if (isSimulationSelected()) {
+
+                               Simulation[] simsCopy = new Simulation[sims.length];
+                               for (int i=0; i < sims.length; i++) {
+                                       simsCopy[i] = sims[i].copy();
+                               }
+                               OpenRocketClipboard.setClipboard(simsCopy);
+
+                               for (Simulation s: sims) {
+                                       document.removeSimulation(s);
+                               }
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       RocketComponent c = getSelectedComponent();
-                       this.setEnabled(isDeletable(c) && isCopyable(c));
+               public void clipboardChanged() {
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       this.setEnabled((isDeletable(c) && isCopyable(c)) || isSimulationSelected());
                }
        }
 
@@ -329,27 +429,36 @@ public class RocketActions {
                public CopyAction() {
                        this.putValue(NAME, "Copy");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_C);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C,
-                                       ActionEvent.CTRL_MASK));
+                       this.putValue(ACCELERATOR_KEY, COPY_KEY_STROKE);
                        this.putValue(SHORT_DESCRIPTION, "Copy this component (and subcomponents) to "
                                        + "the clipboard.");
                        this.putValue(SMALL_ICON, Icons.EDIT_COPY);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isCopyable(c))
-                               return;
-
-                       clipboard = c.copy();
-                       updateClipboardActions();
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+
+                       if (isCopyable(c)) {
+                               OpenRocketClipboard.setClipboard(c.copy());
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       } else if (sims.length >= 0) {
+
+                               Simulation[] simsCopy = new Simulation[sims.length];
+                               for (int i=0; i < sims.length; i++) {
+                                       simsCopy[i] = sims[i].copy();
+                               }
+                               OpenRocketClipboard.setClipboard(simsCopy);
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(isCopyable(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(isCopyable(selectionModel.getSelectedComponent()) ||
+                                       isSimulationSelected());
                }
                
        }
@@ -365,34 +474,53 @@ public class RocketActions {
                public PasteAction() {
                        this.putValue(NAME, "Paste");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_P);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V,
-                                       ActionEvent.CTRL_MASK));
-                       this.putValue(SHORT_DESCRIPTION, "Paste the component (and subcomponents) on "
+                       this.putValue(ACCELERATOR_KEY, PASTE_KEY_STROKE);
+                       this.putValue(SHORT_DESCRIPTION, "Paste the component or simulation on "
                                        + "the clipboard to the design.");
                        this.putValue(SMALL_ICON, Icons.EDIT_PASTE);
-                       update();
-                       
-                       // Listen to when the clipboard changes
-                       clipboardListeners.add(this);
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       Pair<RocketComponent, Integer> position = getPastePosition();
-                       if (position == null)
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       RocketComponent pasted = clipboard.copy();
-                       document.addUndoPosition("Paste " + pasted.getComponentName());
-                       position.getU().addChild(pasted, position.getV());
-                       setSelectedComponent(pasted);
+                       RocketComponent clipboard = OpenRocketClipboard.getClipboardComponent();
+                       Simulation[] sims = OpenRocketClipboard.getClipboardSimulations();
+                       
+                       Pair<RocketComponent, Integer> position = getPastePosition(clipboard);
+                       if (position != null) {
+                               ComponentConfigDialog.hideDialog();
+                               
+                               RocketComponent pasted = clipboard.copy();
+                               document.addUndoPosition("Paste " + pasted.getComponentName());
+                               position.getU().addChild(pasted, position.getV());
+                               selectionModel.setSelectedComponent(pasted);
+                               
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                               
+                       } else if (sims != null) {
+                               
+                               ArrayList<Simulation> copySims = new ArrayList<Simulation>();
+
+                               for (Simulation s: sims) {
+                                       Simulation copy = s.duplicateSimulation(rocket);
+                                       String name = copy.getName();
+                                       if (name.matches(OpenRocketDocument.SIMULATION_NAME_PREFIX + "[0-9]+ *")) {
+                                               copy.setName(document.getNextSimulationName());
+                                       }
+                                       document.addSimulation(copy);
+                                       copySims.add(copy);
+                               }
+                               selectionModel.setSelectedSimulations(copySims.toArray(new Simulation[0]));
+                               
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(getPastePosition() != null);
+               public void clipboardChanged() {
+                       this.setEnabled(
+                                       (getPastePosition(OpenRocketClipboard.getClipboardComponent()) != null) ||
+                                       (OpenRocketClipboard.getClipboardSimulations() != null));
                }
        }
        
@@ -408,12 +536,12 @@ public class RocketActions {
                public EditAction() {
                        this.putValue(NAME, "Edit");
                        this.putValue(SHORT_DESCRIPTION, "Edit the selected component.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
+                       RocketComponent c = selectionModel.getSelectedComponent();
                        if (c == null)
                                return;
                        
@@ -421,8 +549,8 @@ public class RocketActions {
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(getSelectedComponent() != null);
+               public void clipboardChanged() {
+                       this.setEnabled(selectionModel.getSelectedComponent() != null);
                }
        }
 
@@ -439,7 +567,7 @@ public class RocketActions {
                public NewStageAction() {
                        this.putValue(NAME, "New stage");
                        this.putValue(SHORT_DESCRIPTION, "Add a new stage to the rocket design.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
@@ -452,13 +580,13 @@ public class RocketActions {
                        document.addUndoPosition("Add stage");
                        rocket.addChild(stage);
                        rocket.getDefaultConfiguration().setAllStages();
-                       setSelectedComponent(stage);
+                       selectionModel.setSelectedComponent(stage);
                        ComponentConfigDialog.showDialog(parentFrame, document, stage);
                        
                }
 
                @Override
-               public void update() {
+               public void clipboardChanged() {
                        this.setEnabled(true);
                }
        }
@@ -473,12 +601,12 @@ public class RocketActions {
                public MoveUpAction() {
                        this.putValue(NAME, "Move up");
                        this.putValue(SHORT_DESCRIPTION, "Move this component upwards.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent selected = getSelectedComponent();
+                       RocketComponent selected = selectionModel.getSelectedComponent();
                        if (!canMove(selected))
                                return;
                        
@@ -487,12 +615,12 @@ public class RocketActions {
                        RocketComponent parent = selected.getParent();
                        document.addUndoPosition("Move "+selected.getComponentName());
                        parent.moveChild(selected, parent.getChildPosition(selected)-1);
-                       setSelectedComponent(selected);
+                       selectionModel.setSelectedComponent(selected);
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(canMove(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(canMove(selectionModel.getSelectedComponent()));
                }
                
                private boolean canMove(RocketComponent c) {
@@ -514,12 +642,12 @@ public class RocketActions {
                public MoveDownAction() {
                        this.putValue(NAME, "Move down");
                        this.putValue(SHORT_DESCRIPTION, "Move this component downwards.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent selected = getSelectedComponent();
+                       RocketComponent selected = selectionModel.getSelectedComponent();
                        if (!canMove(selected))
                                return;
                        
@@ -528,12 +656,12 @@ public class RocketActions {
                        RocketComponent parent = selected.getParent();
                        document.addUndoPosition("Move "+selected.getComponentName());
                        parent.moveChild(selected, parent.getChildPosition(selected)+1);
-                       setSelectedComponent(selected);
+                       selectionModel.setSelectedComponent(selected);
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(canMove(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(canMove(selectionModel.getSelectedComponent()));
                }
                
                private boolean canMove(RocketComponent c) {
index a4046fb8266962f6a429f7b9e17d06e196d6a8cb..31d204e8dd3657b9cac7e489562c1ff6e8433ee4 100644 (file)
@@ -5,6 +5,7 @@ import java.awt.Color;
 import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.Arrays;
@@ -17,6 +18,8 @@ import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
 import javax.swing.SwingUtilities;
 import javax.swing.table.DefaultTableCellRenderer;
 
@@ -25,6 +28,9 @@ import net.sf.openrocket.aerodynamics.Warning;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.document.events.DocumentChangeEvent;
+import net.sf.openrocket.document.events.DocumentChangeListener;
+import net.sf.openrocket.document.events.SimulationChangeEvent;
 import net.sf.openrocket.gui.adaptors.Column;
 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
 import net.sf.openrocket.gui.components.ResizeLabel;
@@ -43,8 +49,6 @@ public class SimulationPanel extends JPanel {
        private static final Color OK_COLOR = new Color(60,150,0);
        private static final String OK_TEXT = "\u2714";                 // Heavy check mark
        
-       private static final String NAME_PREFIX = "Simulation ";
-
        
        
        private final OpenRocketDocument document;
@@ -70,21 +74,8 @@ public class SimulationPanel extends JPanel {
                button.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
-                               
-                               // Generate unique name for the simulation
-                               int maxValue = 0;
-                               for (Simulation s: document.getSimulations()) {
-                                       String name = s.getName();
-                                       if (name.startsWith(NAME_PREFIX)) {
-                                               try {
-                                                       maxValue = Math.max(maxValue, 
-                                                                       Integer.parseInt(name.substring(NAME_PREFIX.length())));
-                                               } catch (NumberFormatException ignore) { }
-                                       }
-                               }
-
                                Simulation sim = new Simulation(document.getRocket());
-                               sim.setName(NAME_PREFIX + (maxValue+1));
+                               sim.setName(document.getNextSimulationName());
                                
                                int n = document.getSimulationCount();
                                document.addSimulation(sim);
@@ -231,6 +222,7 @@ public class SimulationPanel extends JPanel {
                                                
                                                // Set simulation status icon
                                                Simulation.Status status = document.getSimulation(row).getStatus();
+                                               System.out.println("status=" + status);
                                                label.setIcon(Icons.SIMULATION_STATUS_ICON_MAP.get(status));
                                                
 
@@ -388,11 +380,22 @@ public class SimulationPanel extends JPanel {
                        }
                };
                
-               simulationTable = new JTable(simulationTableModel);
+               // Override processKeyBinding so that the JTable does not catch
+               // key bindings used in menu accelerators
+               simulationTable = new JTable(simulationTableModel) {
+                       @Override
+                       protected boolean processKeyBinding(KeyStroke ks,
+                    KeyEvent e,
+                    int condition,
+                    boolean pressed) {
+                               return false;
+                       }
+               };
                simulationTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                simulationTable.setDefaultRenderer(Object.class, new JLabelRenderer());
                simulationTableModel.setColumnWidths(simulationTable.getColumnModel());
 
+               
                // Mouse listener to act on double-clicks
                simulationTable.addMouseListener(new MouseAdapter() {
                        @Override
@@ -411,6 +414,15 @@ public class SimulationPanel extends JPanel {
                                }
                        }
                });
+               
+               document.addDocumentChangeListener(new DocumentChangeListener() {
+                       @Override
+                       public void documentChanged(DocumentChangeEvent event) {
+                               if (!(event instanceof SimulationChangeEvent))
+                                       return;
+                               simulationTableModel.fireTableDataChanged();
+                       }
+               });
                 
                
                
@@ -431,6 +443,10 @@ public class SimulationPanel extends JPanel {
        }
        
        
+       public ListSelectionModel getSimulationListSelectionModel() {
+               return simulationTable.getSelectionModel();
+       }
+       
        private void openDialog(final Simulation sim, int position) {
                new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), sim, position)
                        .setVisible(true);
@@ -441,6 +457,8 @@ public class SimulationPanel extends JPanel {
                   int[] selection = simulationTable.getSelectedRows();
                   simulationTableModel.fireTableDataChanged();
                   for (int row: selection) {
+                          if (row >= simulationTableModel.getRowCount())
+                                  break;
                           simulationTable.addRowSelectionInterval(row, row);
                   }
        }
index d48010b8b2e46554f517e8fa48649b35cd42b737..f6d7d9de7413591e3cee37bf9a5c3d9096955033 100644 (file)
@@ -121,7 +121,7 @@ public class RocketFigure extends AbstractScaleFigure {
        
        public void setSelection(RocketComponent[] selection) {
                if (selection == null) {
-                       selection = new RocketComponent[0];
+                       this.selection = new RocketComponent[0];
                } else {
                        this.selection = selection;
                }
index c1338231846d8682ebfd5a04890712917b8fd4bc..f5c3116003b2281bf768738857bb510b67ffb033 100644 (file)
@@ -193,7 +193,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
        }
        
        public String getMotorConfigurationDescription() {
-               return rocket.getMotorConfigurationDescription(motorConfiguration);
+               return rocket.getMotorConfigurationNameOrDescription(motorConfiguration);
        }
        
        
index 709c7a59a21a1b2e672ec894428ef7aba6152448..f696a69da0cc7b8241051a3b78825a29214b75f0 100644 (file)
@@ -534,6 +534,42 @@ public class Rocket extends RocketComponent {
        }
 
        
+       /**
+        * Check whether <code>id</code> is a valid motor configuration ID.
+        * 
+        * @param id    the configuration ID.
+        * @return              whether a motor configuration with that ID exists.
+        */
+       public boolean isMotorConfigurationID(String id) {
+               return motorConfigurationIDs.contains(id);
+       }
+       
+       
+       
+       /**
+        * Check whether the given motor configuration ID has motors defined for it.
+        * 
+        * @param id    the motor configuration ID (may be invalid).
+        * @return              whether any motors are defined for it.
+        */
+       public boolean hasMotors(String id) {
+               Iterator<RocketComponent> iterator = this.deepIterator();
+               while (iterator.hasNext()) {
+                       RocketComponent c = iterator.next();
+
+                       if (c instanceof MotorMount) {
+                               MotorMount mount = (MotorMount) c;
+                               if (!mount.isMotorMount())
+                                       continue;
+                               if (mount.getMotor(id) != null) {
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
+       
+       
        /**
         * Return the user-set name of the motor configuration.  If no name has been set,
         * returns an empty string (not null).
@@ -563,9 +599,24 @@ public class Rocket extends RocketComponent {
        
                
        /**
-        * Return a description for the motor configuration.  This is either the 
-        * name previously set by {@link #setMotorConfigurationName(String, String)} or
-        * a string generated from the motor designations of the components.
+        * Return either the motor configuration name (if set) or its description. 
+        * 
+        * @param id  the motor configuration ID.
+        * @return    a textual representation of the configuration
+        */
+       public String getMotorConfigurationNameOrDescription(String id) {
+               String name;
+               
+               name = motorConfigurationNames.get(id);
+               if (name != null  &&  !name.equals(""))
+                       return name;
+               
+               return getMotorConfigurationDescription(id);
+       }
+       
+       /**
+        * Return a description for the motor configuration, generated from the motor 
+        * designations of the components.
         * 
         * @param id  the motor configuration ID.
         * @return    a textual representation of the configuration
@@ -579,10 +630,6 @@ public class Rocket extends RocketComponent {
                        throw new IllegalArgumentException("Motor configuration ID does not exist: "+id);
                }
                
-               name = motorConfigurationNames.get(id);
-               if (name != null  &&  !name.equals(""))
-                       return name;
-               
                // Generate the description
                
                // First iterate over each stage and store the designations of each motor
index 4d932b25148834cf8c33ff3686a09d82e27c2420..8b79bfbc9ef303e4db2618dcafb1e58b2e9d8501 100644 (file)
@@ -80,9 +80,17 @@ public class SimulationConditions implements ChangeSource, Cloneable {
                return motorID;
        }
        
+       /**
+        * Set the motor configuration ID.  This must be a valid motor configuration ID of
+        * the rocket, otherwise the configuration is set to <code>null</code>.
+        * 
+        * @param id    the configuration to set.
+        */
        public void setMotorConfigurationID(String id) {
                if (id != null)
                        id = id.intern();
+               if (!rocket.isMotorConfigurationID(id))
+                       id = null;
                if (id == motorID)
                        return;
                motorID = id;
@@ -319,14 +327,31 @@ public class SimulationConditions implements ChangeSource, Cloneable {
        
        
        public void copyFrom(SimulationConditions src) {
-               if (this.rocket != src.rocket) {
-                       throw new IllegalArgumentException("Unable to copy simulation conditions of "+
-                                       "a difference rocket");
+               
+               if (this.rocket == src.rocket) {
+                       
+                       this.motorID = src.motorID;
+                       
+               } else {
+               
+                       if (src.rocket.hasMotors(src.motorID)) {
+                               // Try to find a matching motor ID
+                               String motorDesc = src.rocket.getMotorConfigurationDescription(src.motorID);
+                               String matchID = null;
+                               
+                               for (String id: this.rocket.getMotorConfigurationIDs()) {
+                                       if (motorDesc.equals(this.rocket.getMotorConfigurationDescription(id))) {
+                                               matchID = id;
+                                               break;
+                                       }
+                               }
+                               
+                               this.motorID = matchID;
+                       } else {
+                               this.motorID = null;
+                       }
                }
-               if (this.equals(src))
-                       return;
                
-               this.motorID = src.motorID;
                this.launchAltitude = src.launchAltitude;
                this.launchLatitude = src.launchLatitude;
                this.launchPressure = src.launchPressure;
index a2120d2122304e1be8073a081ccd5348fedfd67d..0439185510aa912ca440b80cdda9c43508eb5483 100644 (file)
@@ -35,21 +35,21 @@ public class Startup {
                try {
                        
                        Class cls = Class.forName(START_CLASS);
-                       Method m = cls.getMethod("main", String[].class);
+                       Method m = cls.getMethod("main", new Class[] {String[].class});
                        m.invoke(null, new Object[] { args });
                        
                } catch (ClassNotFoundException e) {
                        e.printStackTrace();
-                       error("Error starting main class!", "Please report a bug.");
+                       error(new String[] {"Error starting main class!", "Please report a bug."});
                } catch (NoSuchMethodException e) {
                        e.printStackTrace();
-                       error("Error starting main class!", "Please report a bug.");
+                       error(new String[] {"Error starting main class!", "Please report a bug."});
                } catch (InvocationTargetException e) {
                        e.printStackTrace();
-                       error("Error starting main class!", "Please report a bug.");
+                       error(new String[] {"Error starting main class!", "Please report a bug."});
                } catch (IllegalAccessException e) {
                        e.printStackTrace();
-                       error("Error starting main class!", "Please report a bug.");
+                       error(new String[] {"Error starting main class!", "Please report a bug."});
                }
 
        }
@@ -73,16 +73,16 @@ public class Startup {
                        
                        if (major < REQUIRED_MAJOR_VERSION || 
                                        (major == REQUIRED_MAJOR_VERSION && minor < REQUIRED_MINOR_VERSION)) {
-                               error("Java SE version 6 is required to run OpenRocket.",
+                               error(new String[] {"Java SE version 6 is required to run OpenRocket.",
                                                "You are currently running " + jreName + " version " +
-                                               jreVersion + " by " + jreVendor);
+                                               jreVersion + " by " + jreVendor});
                        }
                        
                } catch (RuntimeException e) {
                        
-                       confirm("The Java version in use could not be detected.",
+                       confirm(new String[] {"The Java version in use could not be detected.",
                                        "OpenRocket requires at least Java SE 6.",
-                                       "Continue anyway?");
+                                       "Continue anyway?"});
                        
                }
                
@@ -118,11 +118,11 @@ public class Startup {
                        String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
                        String jreVendor = System.getProperty("java.vendor", "(unknown)");
 
-                       confirm("OpenJDK is known to have problems running OpenRocket.",
+                       confirm(new String[] {"OpenJDK is known to have problems running OpenRocket.",
                                        " ",
                                        "You are currently running " + jreName + " version " +
                                        jreVersion + " by " + jreVendor,
-                                       "Do you want to continue?");
+                                       "Do you want to continue?"});
                        
                }
        }
@@ -135,7 +135,7 @@ public class Startup {
         * 
         * @param message       an array of messages to present.
         */
-       private static void error(String ... message) {
+       private static void error(String[] message) {
 
                System.err.println();
                System.err.println("Error starting OpenRocket:");
@@ -163,7 +163,7 @@ public class Startup {
         * 
         * @param message       the message Strings to show.
         */
-       private static void confirm(String ... message) {
+       private static void confirm(String[] message) {
 
                if (!GraphicsEnvironment.isHeadless()) {
                        
@@ -171,10 +171,7 @@ public class Startup {
                                        JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
                                System.exit(1);
                        }
-                       
                }
-
        }
        
-       
 }
index 96a32b7ba4e6337a0527e21c51358bc7533d46cf..69a7b8a52f99bee796d2b6910783c3e10624ed2e 100644 (file)
@@ -1,5 +1,6 @@
 package net.sf.openrocket.util;
 
+import java.net.URL;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -18,11 +19,11 @@ public class Icons {
        public static final Map<Simulation.Status, Icon> SIMULATION_STATUS_ICON_MAP;
        static {
                HashMap<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
-               map.put(Simulation.Status.NOT_SIMULATED, new ImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
-               map.put(Simulation.Status.UPTODATE, new ImageIcon("pix/spheres/green-16x16.png", "Up to date"));
-               map.put(Simulation.Status.LOADED, new ImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
-               map.put(Simulation.Status.OUTDATED, new ImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
-               map.put(Simulation.Status.EXTERNAL, new ImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
+               map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
+               map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
+               map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
+               map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
+               map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
                SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
        }
        
@@ -34,23 +35,33 @@ public class Icons {
        }
 
 
-       public static final Icon FILE_NEW = new ImageIcon(ClassLoader.getSystemResource("pix/icons/document-new.png"), "New document");
-       public static final Icon FILE_OPEN = new ImageIcon(ClassLoader.getSystemResource("pix/icons/document-open.png"), "Open document");
-       public static final Icon FILE_SAVE = new ImageIcon(ClassLoader.getSystemResource("pix/icons/document-save.png"), "Save document");
-       public static final Icon FILE_SAVE_AS = new ImageIcon(ClassLoader.getSystemResource("pix/icons/document-save-as.png"), "Save document as");
-       public static final Icon FILE_CLOSE = new ImageIcon(ClassLoader.getSystemResource("pix/icons/document-close.png"), "Close document");
-       public static final Icon FILE_QUIT = new ImageIcon(ClassLoader.getSystemResource("pix/icons/application-exit.png"), "Quit OpenRocket");
+       public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
+       public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
+       public static final Icon FILE_SAVE = loadImageIcon("pix/icons/document-save.png", "Save document");
+       public static final Icon FILE_SAVE_AS = loadImageIcon("pix/icons/document-save-as.png", "Save document as");
+       public static final Icon FILE_CLOSE = loadImageIcon("pix/icons/document-close.png", "Close document");
+       public static final Icon FILE_QUIT = loadImageIcon("pix/icons/application-exit.png", "Quit OpenRocket");
        
-       public static final Icon EDIT_UNDO = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-undo.png"), "Undo");
-       public static final Icon EDIT_REDO = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-redo.png"), "Redo");
-       public static final Icon EDIT_CUT = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-cut.png"), "Cut");
-       public static final Icon EDIT_COPY = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-copy.png"), "Copy");
-       public static final Icon EDIT_PASTE = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-paste.png"), "Paste");
-       public static final Icon EDIT_DELETE = new ImageIcon(ClassLoader.getSystemResource("pix/icons/edit-delete.png"), "Delete");
+       public static final Icon EDIT_UNDO = loadImageIcon("pix/icons/edit-undo.png", "Undo");
+       public static final Icon EDIT_REDO = loadImageIcon("pix/icons/edit-redo.png", "Redo");
+       public static final Icon EDIT_CUT = loadImageIcon("pix/icons/edit-cut.png", "Cut");
+       public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
+       public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
+       public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
 
-       public static final Icon ZOOM_IN = new ImageIcon(ClassLoader.getSystemResource("pix/icons/zoom-in.png"), "Zoom in");
-       public static final Icon ZOOM_OUT = new ImageIcon(ClassLoader.getSystemResource("pix/icons/zoom-out.png"), "Zoom out");
+       public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
+       public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
 
-       public static final Icon PREFERENCES = new ImageIcon(ClassLoader.getSystemResource("pix/icons/preferences.png"), "Preferences");
+       public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
 
+       
+       
+       private static ImageIcon loadImageIcon(String file, String name) {
+               URL url = ClassLoader.getSystemResource(file);
+               if (url == null) {
+                       System.err.println("Resource "+file+" not found!  Ignoring...");
+                       return null;
+               }
+               return new ImageIcon(url, name);
+       }
 }
index dbb31c286f58c02bce265b86875e46bc206f22cd..23024e54129a3a87dfe4450d47ea7cc55c4e8521 100644 (file)
@@ -5,8 +5,12 @@ import java.awt.Dimension;
 import java.awt.Point;
 import java.awt.Toolkit;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
 import java.util.prefs.BackingStoreException;
 import java.util.prefs.Preferences;
 
@@ -46,7 +50,37 @@ public class Prefs {
        
        
        
-       private static final String VERSION = "0.9.0";
+       private static final String BUILD_VERSION;
+       private static final String BUILD_SOURCE;
+       
+       static {
+               try {
+                       InputStream is = ClassLoader.getSystemResourceAsStream("build.properties");
+                       if (is == null) {
+                               throw new MissingResourceException(
+                                               "build.properties not found, distribution built wrong",
+                                               "build.properties", "build.version");
+                       }
+                       
+                       Properties props = new Properties();
+                       props.load(is);
+                       is.close();
+                       
+                       BUILD_VERSION = props.getProperty("build.version");
+                       if (BUILD_VERSION == null) {
+                               throw new MissingResourceException(
+                                               "build.version not found in property file",
+                                               "build.properties", "build.version");
+                       }
+                       
+                       BUILD_SOURCE = props.getProperty("build.source");
+                       
+               } catch (IOException e) {
+                       throw new MissingResourceException(
+                                       "Error reading build.properties",
+                                       "build.properties", "build.version");
+               }
+       }
        
        
        public static final String BODY_COMPONENT_INSERT_POSITION_KEY = "BodyComponentInsertPosition";
@@ -112,7 +146,12 @@ public class Prefs {
        
        
        public static String getVersion() {
-               return VERSION;
+               return BUILD_VERSION;
+       }
+       
+       
+       public static String getBuildSource() {
+               return BUILD_SOURCE;
        }