updates for 0.9.4
This commit is contained in:
parent
e3b951cb9e
commit
88139aadac
10
.classpath
10
.classpath
@ -1,13 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="extra-src"/>
|
<classpathentry kind="src" path="src-extra"/>
|
||||||
<classpathentry kind="src" path="test"/>
|
<classpathentry kind="src" path="test"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
<classpathentry kind="lib" path="/home/sampo/Projects/OpenRocket/lib/miglayout15-swing.jar"/>
|
<classpathentry kind="lib" path="/home/sampo/Projects/OpenRocket/lib/miglayout15-swing.jar"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JCommon 1.0.16"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JCommon 1.0.16"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JFreeChart 1.0.13"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JFreeChart 1.0.13"/>
|
||||||
<classpathentry kind="lib" path="/home/sampo/Projects/OpenRocket/extra-lib/RXTXcomm.jar"/>
|
<classpathentry kind="lib" path="lib-test/hamcrest-core-1.1.jar"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
<classpathentry kind="lib" path="lib-test/hamcrest-library-1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib-test/jmock-2.5.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib-test/jmock-junit4-2.5.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib-extra/RXTXcomm.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib-test/junit-4.7.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@ -1,3 +1,12 @@
|
|||||||
|
2009-10-04 Sampo Niskanen
|
||||||
|
|
||||||
|
* [BUG] Fixed too high configuration dialogs
|
||||||
|
|
||||||
|
2009-10-03 Sampo Niskanen
|
||||||
|
|
||||||
|
* Added debug information to ant build file compilation
|
||||||
|
* Implemented update information fetching (client side)
|
||||||
|
|
||||||
2009-09-26 Sampo Niskanen
|
2009-09-26 Sampo Niskanen
|
||||||
|
|
||||||
* Implemented custom material editing
|
* Implemented custom material editing
|
||||||
|
|||||||
13
TODO
13
TODO
@ -4,7 +4,6 @@ Feature roadmap for OpenRocket 1.0
|
|||||||
|
|
||||||
Must-have:
|
Must-have:
|
||||||
|
|
||||||
- Allow editing user-defined materials
|
|
||||||
- Go through thrust curves and correct errors
|
- Go through thrust curves and correct errors
|
||||||
- Add styrofoam and depron materials
|
- Add styrofoam and depron materials
|
||||||
|
|
||||||
@ -12,12 +11,13 @@ Must-have:
|
|||||||
Bugs:
|
Bugs:
|
||||||
|
|
||||||
- Simulation plot dialog forces dialog one button row too high (All/None)
|
- Simulation plot dialog forces dialog one button row too high (All/None)
|
||||||
- All configuration dialogs too high
|
- Unit tests fail from ant script
|
||||||
|
|
||||||
|
|
||||||
Maybe:
|
Maybe:
|
||||||
|
|
||||||
- Windows executable wrapper (launch4j)
|
- Windows executable wrapper (launch4j)
|
||||||
|
- Inform user about software updates
|
||||||
|
|
||||||
|
|
||||||
Postponed:
|
Postponed:
|
||||||
@ -31,18 +31,21 @@ Postponed:
|
|||||||
- Simulate other branches
|
- Simulate other branches
|
||||||
- Implement setDefaults() method for RocketComponent
|
- Implement setDefaults() method for RocketComponent
|
||||||
- BUG: Inner tube cluster rotation, edit with spinner arrows, slider wrong
|
- BUG: Inner tube cluster rotation, edit with spinner arrows, slider wrong
|
||||||
- Inform user about software updates
|
|
||||||
- Reading thrust curves from external directory
|
- Reading thrust curves from external directory
|
||||||
- NAR/CNES/etc competition validity checking
|
- NAR/CNES/etc competition validity checking
|
||||||
|
- Running from command line
|
||||||
|
- Print support
|
||||||
|
- Saving as SVG
|
||||||
|
|
||||||
|
|
||||||
Refactoring tasks:
|
Refactoring tasks:
|
||||||
|
|
||||||
|
- Move startup class to src14 directory, remove reflection
|
||||||
- Remove database etc. initialization from class initialization,
|
- Remove database etc. initialization from class initialization,
|
||||||
create separate set of test motors
|
create separate set of test motors
|
||||||
- Extract event rules and data saving from Simulator into listeners
|
- Extract event rules and data saving from Simulator into listeners
|
||||||
- Change SimulationStatus to include methods for obtaining basic
|
- Change SimulationStatus to include methods for obtaining basic
|
||||||
position (maybe even an interface)
|
position (maybe even change to an interface, implements Cloneable)
|
||||||
- Change Motor (immutable) to be a factory of MotorInstance (stateful)
|
- Change Motor (immutable) to be a factory of MotorInstance (stateful)
|
||||||
|
|
||||||
|
|
||||||
@ -74,4 +77,6 @@ In 0.9.4:
|
|||||||
- Save file as oldest OpenRocket format possible (for 0.9.4)
|
- Save file as oldest OpenRocket format possible (for 0.9.4)
|
||||||
- Non-exception bug handling
|
- Non-exception bug handling
|
||||||
- JTree text is cropped unnecessarily
|
- JTree text is cropped unnecessarily
|
||||||
|
- Allow editing user-defined materials
|
||||||
|
- [BUG] All configuration dialogs too high
|
||||||
|
|
||||||
|
|||||||
@ -10,3 +10,7 @@ build.version=0.9.4pre
|
|||||||
|
|
||||||
build.source=default
|
build.source=default
|
||||||
|
|
||||||
|
|
||||||
|
# Whether checking for updates is enabled by default.
|
||||||
|
|
||||||
|
build.checkupdates=true
|
||||||
|
|||||||
10
build.xml
10
build.xml
@ -33,9 +33,11 @@
|
|||||||
|
|
||||||
<path id="test-classpath">
|
<path id="test-classpath">
|
||||||
<path refid="classpath"/>
|
<path refid="classpath"/>
|
||||||
|
<pathelement location="${basedir}"/>
|
||||||
<pathelement location="${build-test.dir}"/>
|
<pathelement location="${build-test.dir}"/>
|
||||||
<pathelement location="${classes.dir}"/>
|
<pathelement location="${classes.dir}"/>
|
||||||
<pathelement location="${ant.library.dir}/junit4.jar"/>
|
<!-- <pathelement location="${ant.library.dir}/junit4.jar"/> -->
|
||||||
|
<pathelement location="lib-test/junit-4.7.jar"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
|
|
||||||
@ -51,9 +53,9 @@
|
|||||||
<target name="build">
|
<target name="build">
|
||||||
<mkdir dir="${classes.dir}"/>
|
<mkdir dir="${classes.dir}"/>
|
||||||
<echo>Compiling main classes</echo>
|
<echo>Compiling main classes</echo>
|
||||||
<javac srcdir="${src.dir}" destdir="${classes.dir}" excludes="${main-dir}/*" classpathref="classpath"/>
|
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" excludes="${main-dir}/*" classpathref="classpath"/>
|
||||||
<echo>Compiling startup classes</echo>
|
<echo>Compiling startup classes</echo>
|
||||||
<javac srcdir="${src.dir}/${main-dir}" destdir="${classes.dir}" source="1.4" classpathref="classpath"/>
|
<javac debug="true" srcdir="${src.dir}/${main-dir}" destdir="${classes.dir}" source="1.4" classpathref="classpath"/>
|
||||||
<copy file="build.properties" todir="${dist.dir}"/>
|
<copy file="build.properties" todir="${dist.dir}"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -150,7 +152,7 @@ ${criticaltodos}</fail>
|
|||||||
<target name="unittest" description="Execute unit tests" depends="build">
|
<target name="unittest" description="Execute unit tests" depends="build">
|
||||||
<echo>Building unit tests</echo>
|
<echo>Building unit tests</echo>
|
||||||
<mkdir dir="${build-test.dir}"/>
|
<mkdir dir="${build-test.dir}"/>
|
||||||
<javac srcdir="${src-test.dir}" destdir="${build-test.dir}" classpathref="test-classpath"/>
|
<javac debug="true" srcdir="${src-test.dir}" destdir="${build-test.dir}" classpathref="test-classpath"/>
|
||||||
|
|
||||||
<echo>Running unit tests</echo>
|
<echo>Running unit tests</echo>
|
||||||
<mkdir dir="tmp/rawtestoutput"/>
|
<mkdir dir="tmp/rawtestoutput"/>
|
||||||
|
|||||||
BIN
lib-test/hamcrest-core-1.1.jar
Normal file
BIN
lib-test/hamcrest-core-1.1.jar
Normal file
Binary file not shown.
BIN
lib-test/hamcrest-library-1.1.jar
Normal file
BIN
lib-test/hamcrest-library-1.1.jar
Normal file
Binary file not shown.
BIN
lib-test/jmock-2.5.1.jar
Normal file
BIN
lib-test/jmock-2.5.1.jar
Normal file
Binary file not shown.
BIN
lib-test/jmock-junit4-2.5.1.jar
Normal file
BIN
lib-test/jmock-junit4-2.5.1.jar
Normal file
Binary file not shown.
BIN
lib-test/junit-4.7.jar
Normal file
BIN
lib-test/junit-4.7.jar
Normal file
Binary file not shown.
58
src/net/sf/openrocket/communication/BugReporter.java
Normal file
58
src/net/sf/openrocket/communication/BugReporter.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
import net.sf.openrocket.util.Prefs;
|
||||||
|
|
||||||
|
public class BugReporter extends Communicator {
|
||||||
|
|
||||||
|
// Inhibit instantiation
|
||||||
|
private BugReporter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the provided report to the OpenRocket bug report URL. If the connection
|
||||||
|
* fails or the server does not respond with the correct response code, an
|
||||||
|
* exception is thrown.
|
||||||
|
*
|
||||||
|
* @param report the report to send.
|
||||||
|
* @throws IOException if an error occurs while connecting to the server or
|
||||||
|
* the server responds with a wrong response code.
|
||||||
|
*/
|
||||||
|
public static void sendBugReport(String report) throws IOException {
|
||||||
|
|
||||||
|
HttpURLConnection connection = connectionSource.getConnection(BUG_REPORT_URL);
|
||||||
|
|
||||||
|
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
||||||
|
connection.setInstanceFollowRedirects(true);
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
connection.setRequestProperty("X-OpenRocket-Version", encode(Prefs.getVersion()));
|
||||||
|
|
||||||
|
String post;
|
||||||
|
post = (VERSION_PARAM + "=" + encode(Prefs.getVersion())
|
||||||
|
+ "&" + BUG_REPORT_PARAM + "=" + encode(report));
|
||||||
|
|
||||||
|
OutputStreamWriter wr = null;
|
||||||
|
try {
|
||||||
|
// Send post information
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
|
||||||
|
wr.write(post);
|
||||||
|
wr.flush();
|
||||||
|
|
||||||
|
if (connection.getResponseCode() != BUG_REPORT_RESPONSE_CODE) {
|
||||||
|
throw new IOException("Server responded with code " +
|
||||||
|
connection.getResponseCode() + ", expecting " + BUG_REPORT_RESPONSE_CODE);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (wr != null)
|
||||||
|
wr.close();
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,262 +0,0 @@
|
|||||||
package net.sf.openrocket.communication;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import net.sf.openrocket.util.ComparablePair;
|
|
||||||
import net.sf.openrocket.util.Prefs;
|
|
||||||
|
|
||||||
public class Communication {
|
|
||||||
|
|
||||||
private static final String BUG_REPORT_URL =
|
|
||||||
"http://openrocket.sourceforge.net/actions/reportbug";
|
|
||||||
private static final String UPDATE_INFO_URL =
|
|
||||||
"http://openrocket.sourceforge.net/actions/updates";
|
|
||||||
|
|
||||||
private static final String VERSION_PARAM = "version";
|
|
||||||
|
|
||||||
|
|
||||||
private static final String BUG_REPORT_PARAM = "content";
|
|
||||||
private static final int BUG_REPORT_RESPONSE_CODE = HttpURLConnection.HTTP_ACCEPTED;
|
|
||||||
private static final int CONNECTION_TIMEOUT = 10000; // in milliseconds
|
|
||||||
|
|
||||||
private static final int UPDATE_INFO_UPDATE_AVAILABLE = HttpURLConnection.HTTP_OK;
|
|
||||||
private static final int UPDATE_INFO_NO_UPDATE_CODE = HttpURLConnection.HTTP_NO_CONTENT;
|
|
||||||
private static final String UPDATE_INFO_CONTENT_TYPE = "text/plain";
|
|
||||||
|
|
||||||
|
|
||||||
private static UpdateInfoFetcher fetcher = null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the provided report to the OpenRocket bug report URL. If the connection
|
|
||||||
* fails or the server does not respond with the correct response code, an
|
|
||||||
* exception is thrown.
|
|
||||||
*
|
|
||||||
* @param report the report to send.
|
|
||||||
* @throws IOException if an error occurs while connecting to the server or
|
|
||||||
* the server responds with a wrong response code.
|
|
||||||
*/
|
|
||||||
public static void sendBugReport(String report) throws IOException {
|
|
||||||
URL url = new URL(BUG_REPORT_URL);
|
|
||||||
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
|
|
||||||
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
|
||||||
connection.setInstanceFollowRedirects(true);
|
|
||||||
connection.setRequestMethod("POST");
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setRequestProperty("X-OpenRocket-Version", encode(Prefs.getVersion()));
|
|
||||||
|
|
||||||
String post;
|
|
||||||
post = (VERSION_PARAM + "=" + encode(Prefs.getVersion())
|
|
||||||
+ "&" + BUG_REPORT_PARAM + "=" + encode(report));
|
|
||||||
|
|
||||||
OutputStreamWriter wr = null;
|
|
||||||
try {
|
|
||||||
// Send post information
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
|
|
||||||
wr.write(post);
|
|
||||||
wr.flush();
|
|
||||||
|
|
||||||
if (connection.getResponseCode() != BUG_REPORT_RESPONSE_CODE) {
|
|
||||||
throw new IOException("Server responded with code " +
|
|
||||||
connection.getResponseCode() + ", expecting " + BUG_REPORT_RESPONSE_CODE);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (wr != null)
|
|
||||||
wr.close();
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start an asynchronous task that will fetch information about the latest
|
|
||||||
* OpenRocket version. This will overwrite any previous fetching operation.
|
|
||||||
*/
|
|
||||||
public static void startFetchUpdateInfo() {
|
|
||||||
fetcher = new UpdateInfoFetcher();
|
|
||||||
fetcher.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the update info fetching is still in progress.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if the communication is still in progress.
|
|
||||||
*/
|
|
||||||
public static boolean isFetchUpdateInfoRunning() {
|
|
||||||
if (fetcher == null) {
|
|
||||||
throw new IllegalStateException("startFetchUpdateInfo() has not been called");
|
|
||||||
}
|
|
||||||
return fetcher.isAlive();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the result of the background update info fetcher. This method returns
|
|
||||||
* the result of the previous call to {@link #startFetchUpdateInfo()}. It must be
|
|
||||||
* called before calling this method.
|
|
||||||
* <p>
|
|
||||||
* This method will return <code>null</code> if the info fetcher is still running or
|
|
||||||
* if it encountered a problem in communicating with the server. The difference can
|
|
||||||
* be checked using {@link #isFetchUpdateInfoRunning()}.
|
|
||||||
*
|
|
||||||
* @return the update result, or <code>null</code> if the fetching is still in progress
|
|
||||||
* or an error occurred while communicating with the server.
|
|
||||||
* @throws IllegalStateException if {@link #startFetchUpdateInfo()} has not been called.
|
|
||||||
*/
|
|
||||||
public static UpdateInfo getUpdateInfo() {
|
|
||||||
if (fetcher == null) {
|
|
||||||
throw new IllegalStateException("startFetchUpdateInfo() has not been called");
|
|
||||||
}
|
|
||||||
return fetcher.info;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the data received from the server.
|
|
||||||
*
|
|
||||||
* @param r the Reader from which to read.
|
|
||||||
* @return an UpdateInfo construct, or <code>null</code> if the data was invalid.
|
|
||||||
* @throws IOException if an I/O exception occurs.
|
|
||||||
*/
|
|
||||||
/* package-private */
|
|
||||||
static UpdateInfo parseUpdateInput(Reader r) throws IOException {
|
|
||||||
BufferedReader reader;
|
|
||||||
if (r instanceof BufferedReader) {
|
|
||||||
reader = (BufferedReader)r;
|
|
||||||
} else {
|
|
||||||
reader = new BufferedReader(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String version = null;
|
|
||||||
ArrayList<ComparablePair<Integer,String>> updates =
|
|
||||||
new ArrayList<ComparablePair<Integer,String>>();
|
|
||||||
|
|
||||||
String str = reader.readLine();
|
|
||||||
while (str != null) {
|
|
||||||
if (str.matches("^Version: *[0-9]+\\.[0-9]+\\.[0-9]+[a-zA-Z0-9.-]* *$")) {
|
|
||||||
version = str.substring(8).trim();
|
|
||||||
} else if (str.matches("^[0-9]+:\\p{Print}+$")) {
|
|
||||||
int index = str.indexOf(':');
|
|
||||||
int value = Integer.parseInt(str.substring(0, index));
|
|
||||||
String desc = str.substring(index+1).trim();
|
|
||||||
if (!desc.equals("")) {
|
|
||||||
updates.add(new ComparablePair<Integer,String>(value, desc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ignore anything else
|
|
||||||
str = reader.readLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version != null) {
|
|
||||||
return new UpdateInfo(version, updates);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class UpdateInfoFetcher extends Thread {
|
|
||||||
|
|
||||||
private volatile UpdateInfo info = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
doConnection();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void doConnection() throws IOException {
|
|
||||||
URL url;
|
|
||||||
url = new URL(UPDATE_INFO_URL + "?" + VERSION_PARAM + "=" +
|
|
||||||
encode(Prefs.getVersion()));
|
|
||||||
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
|
|
||||||
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
|
||||||
connection.setInstanceFollowRedirects(true);
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setRequestProperty("X-OpenRocket-Version", encode(Prefs.getVersion()));
|
|
||||||
connection.setRequestProperty("X-OpenRocket-ID", encode(Prefs.getUniqueID()));
|
|
||||||
connection.setRequestProperty("X-OpenRocket-OS", encode(
|
|
||||||
System.getProperty("os.name") + " " + System.getProperty("os.arch")));
|
|
||||||
connection.setRequestProperty("X-OpenRocket-Java", encode(
|
|
||||||
System.getProperty("java.vendor") + " " + System.getProperty("java.version")));
|
|
||||||
connection.setRequestProperty("X-OpenRocket-Country", encode(
|
|
||||||
System.getProperty("user.country")));
|
|
||||||
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
connection.connect();
|
|
||||||
|
|
||||||
if (connection.getResponseCode() == UPDATE_INFO_NO_UPDATE_CODE) {
|
|
||||||
// No updates are available
|
|
||||||
info = new UpdateInfo();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection.getResponseCode() != UPDATE_INFO_UPDATE_AVAILABLE) {
|
|
||||||
// Error communicating with server
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UPDATE_INFO_CONTENT_TYPE.equalsIgnoreCase(connection.getContentType())) {
|
|
||||||
// Unknown response type
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is available, parse input
|
|
||||||
is = connection.getInputStream();
|
|
||||||
String encoding = connection.getContentEncoding();
|
|
||||||
if (encoding == null)
|
|
||||||
encoding = "UTF-8";
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is, encoding));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (is != null)
|
|
||||||
is.close();
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String encode(String str) {
|
|
||||||
if (str == null)
|
|
||||||
return "null";
|
|
||||||
try {
|
|
||||||
return URLEncoder.encode(str, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new RuntimeException("Unsupported encoding UTF-8", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
72
src/net/sf/openrocket/communication/Communicator.java
Normal file
72
src/net/sf/openrocket/communication/Communicator.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
public abstract class Communicator {
|
||||||
|
|
||||||
|
protected static final String BUG_REPORT_URL;
|
||||||
|
|
||||||
|
protected static final String UPDATE_INFO_URL;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String url;
|
||||||
|
url = System.getProperty("openrocket.debug.bugurl");
|
||||||
|
if (url == null)
|
||||||
|
url = "http://openrocket.sourceforge.net/actions/reportbug";
|
||||||
|
BUG_REPORT_URL = url;
|
||||||
|
|
||||||
|
url = System.getProperty("openrocket.debug.updateurl");
|
||||||
|
if (url == null)
|
||||||
|
url = "http://openrocket.sourceforge.net/actions/updates";
|
||||||
|
UPDATE_INFO_URL = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static final String VERSION_PARAM = "version";
|
||||||
|
|
||||||
|
|
||||||
|
protected static final String BUG_REPORT_PARAM = "content";
|
||||||
|
protected static final int BUG_REPORT_RESPONSE_CODE = HttpURLConnection.HTTP_ACCEPTED;
|
||||||
|
protected static final int CONNECTION_TIMEOUT = 10000; // in milliseconds
|
||||||
|
|
||||||
|
protected static final int UPDATE_INFO_UPDATE_AVAILABLE = HttpURLConnection.HTTP_OK;
|
||||||
|
protected static final int UPDATE_INFO_NO_UPDATE_CODE = HttpURLConnection.HTTP_NO_CONTENT;
|
||||||
|
protected static final String UPDATE_INFO_CONTENT_TYPE = "text/plain";
|
||||||
|
|
||||||
|
// Limit the number of bytes that can be read from the server
|
||||||
|
protected static final int MAX_INPUT_BYTES = 20000;
|
||||||
|
|
||||||
|
|
||||||
|
protected static ConnectionSource connectionSource = new DefaultConnectionSource();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the source of the network connections. This can be used for unit testing.
|
||||||
|
* By default the source is a DefaultConnectionSource.
|
||||||
|
*
|
||||||
|
* @param source the source of the connections.
|
||||||
|
*/
|
||||||
|
public static void setConnectionSource(ConnectionSource source) {
|
||||||
|
connectionSource = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL-encode the specified string in UTF-8 encoding.
|
||||||
|
*
|
||||||
|
* @param str the string to encode (null ok)
|
||||||
|
* @return the encoded string or "null"
|
||||||
|
*/
|
||||||
|
public static String encode(String str) {
|
||||||
|
if (str == null)
|
||||||
|
return "null";
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(str, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException("Unsupported encoding UTF-8", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
src/net/sf/openrocket/communication/ConnectionSource.java
Normal file
21
src/net/sf/openrocket/communication/ConnectionSource.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A source for network connections. This interface exists to enable unit testing.
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
public interface ConnectionSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a connection to the specified url.
|
||||||
|
* @param url the URL to connect to.
|
||||||
|
* @return the corresponding HttpURLConnection
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
|
*/
|
||||||
|
public HttpURLConnection getConnection(String url) throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of ConnectionSource, which simply opens a new
|
||||||
|
* HttpURLConnection from a URL object.
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
public class DefaultConnectionSource implements ConnectionSource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpURLConnection getConnection(String urlString) throws IOException {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
return (HttpURLConnection) url.openConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
226
src/net/sf/openrocket/communication/UpdateInfoRetriever.java
Normal file
226
src/net/sf/openrocket/communication/UpdateInfoRetriever.java
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import net.sf.openrocket.util.ComparablePair;
|
||||||
|
import net.sf.openrocket.util.LimitedInputStream;
|
||||||
|
import net.sf.openrocket.util.Prefs;
|
||||||
|
|
||||||
|
public class UpdateInfoRetriever {
|
||||||
|
|
||||||
|
private UpdateInfoFetcher fetcher = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start an asynchronous task that will fetch information about the latest
|
||||||
|
* OpenRocket version. This will overwrite any previous fetching operation.
|
||||||
|
* This call will return immediately.
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
fetcher = new UpdateInfoFetcher();
|
||||||
|
fetcher.setDaemon(true);
|
||||||
|
fetcher.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the update info fetching is still in progress.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the communication is still in progress.
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
if (fetcher == null) {
|
||||||
|
throw new IllegalStateException("startFetchUpdateInfo() has not been called");
|
||||||
|
}
|
||||||
|
return fetcher.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the result of the background update info fetcher. This method returns
|
||||||
|
* the result of the previous call to {@link #start()}. It must be
|
||||||
|
* called before calling this method.
|
||||||
|
* <p>
|
||||||
|
* This method will return <code>null</code> if the info fetcher is still running or
|
||||||
|
* if it encountered a problem in communicating with the server. The difference can
|
||||||
|
* be checked using {@link #isRunning()}.
|
||||||
|
*
|
||||||
|
* @return the update result, or <code>null</code> if the fetching is still in progress
|
||||||
|
* or an error occurred while communicating with the server.
|
||||||
|
* @throws IllegalStateException if {@link #start()} has not been called.
|
||||||
|
*/
|
||||||
|
public UpdateInfo getUpdateInfo() {
|
||||||
|
if (fetcher == null) {
|
||||||
|
throw new IllegalStateException("start() has not been called");
|
||||||
|
}
|
||||||
|
return fetcher.info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the data received from the server.
|
||||||
|
*
|
||||||
|
* @param r the Reader from which to read.
|
||||||
|
* @return an UpdateInfo construct, or <code>null</code> if the data was invalid.
|
||||||
|
* @throws IOException if an I/O exception occurs.
|
||||||
|
*/
|
||||||
|
/* package-private */
|
||||||
|
static UpdateInfo parseUpdateInput(Reader r) throws IOException {
|
||||||
|
BufferedReader reader;
|
||||||
|
if (r instanceof BufferedReader) {
|
||||||
|
reader = (BufferedReader)r;
|
||||||
|
} else {
|
||||||
|
reader = new BufferedReader(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String version = null;
|
||||||
|
ArrayList<ComparablePair<Integer,String>> updates =
|
||||||
|
new ArrayList<ComparablePair<Integer,String>>();
|
||||||
|
|
||||||
|
String str = reader.readLine();
|
||||||
|
while (str != null) {
|
||||||
|
if (str.matches("^Version: *[0-9]+\\.[0-9]+\\.[0-9]+[a-zA-Z0-9.-]* *$")) {
|
||||||
|
version = str.substring(8).trim();
|
||||||
|
} else if (str.matches("^[0-9]+:\\p{Print}+$")) {
|
||||||
|
int index = str.indexOf(':');
|
||||||
|
int value = Integer.parseInt(str.substring(0, index));
|
||||||
|
String desc = str.substring(index+1).trim();
|
||||||
|
if (!desc.equals("")) {
|
||||||
|
updates.add(new ComparablePair<Integer,String>(value, desc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ignore anything else
|
||||||
|
str = reader.readLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version != null) {
|
||||||
|
return new UpdateInfo(version, updates);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An asynchronous task that fetches and parses the update info.
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
private class UpdateInfoFetcher extends Thread {
|
||||||
|
|
||||||
|
private volatile UpdateInfo info = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
doConnection();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void doConnection() throws IOException {
|
||||||
|
String url = Communicator.UPDATE_INFO_URL + "?" + Communicator.VERSION_PARAM + "="
|
||||||
|
+ Communicator.encode(Prefs.getVersion());
|
||||||
|
|
||||||
|
HttpURLConnection connection = Communicator.connectionSource.getConnection(url);
|
||||||
|
|
||||||
|
connection.setConnectTimeout(Communicator.CONNECTION_TIMEOUT);
|
||||||
|
connection.setInstanceFollowRedirects(true);
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setRequestProperty("X-OpenRocket-Version",
|
||||||
|
Communicator.encode(Prefs.getVersion()));
|
||||||
|
connection.setRequestProperty("X-OpenRocket-ID",
|
||||||
|
Communicator.encode(Prefs.getUniqueID()));
|
||||||
|
connection.setRequestProperty("X-OpenRocket-OS",
|
||||||
|
Communicator.encode(System.getProperty("os.name") + " " +
|
||||||
|
System.getProperty("os.arch")));
|
||||||
|
connection.setRequestProperty("X-OpenRocket-Java",
|
||||||
|
Communicator.encode(System.getProperty("java.vendor") + " " +
|
||||||
|
System.getProperty("java.version")));
|
||||||
|
connection.setRequestProperty("X-OpenRocket-Country",
|
||||||
|
Communicator.encode(System.getProperty("user.country") + " " +
|
||||||
|
Communicator.encode(System.getProperty("user.timezone"))));
|
||||||
|
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
if (connection.getResponseCode() == Communicator.UPDATE_INFO_NO_UPDATE_CODE) {
|
||||||
|
// No updates are available
|
||||||
|
info = new UpdateInfo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection.getResponseCode() != Communicator.UPDATE_INFO_UPDATE_AVAILABLE) {
|
||||||
|
// Error communicating with server
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Communicator.UPDATE_INFO_CONTENT_TYPE.equalsIgnoreCase(
|
||||||
|
connection.getContentType())) {
|
||||||
|
// Unknown response type
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Update is available, parse input
|
||||||
|
is = connection.getInputStream();
|
||||||
|
is = new LimitedInputStream(is, Communicator.MAX_INPUT_BYTES);
|
||||||
|
String encoding = connection.getContentEncoding();
|
||||||
|
if (encoding == null || encoding.equals(""))
|
||||||
|
encoding = "UTF-8";
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is, encoding));
|
||||||
|
|
||||||
|
String version = null;
|
||||||
|
ArrayList<ComparablePair<Integer, String>> updates =
|
||||||
|
new ArrayList<ComparablePair<Integer, String>>();
|
||||||
|
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (line != null) {
|
||||||
|
|
||||||
|
if (line.matches("^Version:[a-zA-Z0-9._ -]{1,30}$")) {
|
||||||
|
version = line.substring(8).trim();
|
||||||
|
} else if (line.matches("^[0-9]{1,9}:\\P{Cntrl}{1,300}$")) {
|
||||||
|
String[] split = line.split(":", 2);
|
||||||
|
int n = Integer.parseInt(split[0]);
|
||||||
|
updates.add(new ComparablePair<Integer,String>(n, split[1].trim()));
|
||||||
|
}
|
||||||
|
// Ignore line otherwise
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check version input
|
||||||
|
if (version == null || version.length() == 0 ||
|
||||||
|
version.equalsIgnoreCase(Prefs.getVersion())) {
|
||||||
|
// Invalid response
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
info = new UpdateInfo(version, updates);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (is != null)
|
||||||
|
is.close();
|
||||||
|
connection.disconnect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -79,6 +79,7 @@ public class Databases {
|
|||||||
BULK_MATERIAL.add(new Material.Bulk("Cardboard", 680, false));
|
BULK_MATERIAL.add(new Material.Bulk("Cardboard", 680, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Carbon fiber", 1780, false));
|
BULK_MATERIAL.add(new Material.Bulk("Carbon fiber", 1780, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Cork", 240, false));
|
BULK_MATERIAL.add(new Material.Bulk("Cork", 240, false));
|
||||||
|
BULK_MATERIAL.add(new Material.Bulk("Depron", 40, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Fiberglass", 1850, false));
|
BULK_MATERIAL.add(new Material.Bulk("Fiberglass", 1850, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Kraft phenolic",950, false));
|
BULK_MATERIAL.add(new Material.Bulk("Kraft phenolic",950, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Maple", 755, false));
|
BULK_MATERIAL.add(new Material.Bulk("Maple", 755, false));
|
||||||
@ -89,6 +90,7 @@ public class Databases {
|
|||||||
BULK_MATERIAL.add(new Material.Bulk("Polystyrene", 1050, false));
|
BULK_MATERIAL.add(new Material.Bulk("Polystyrene", 1050, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("PVC", 1390, false));
|
BULK_MATERIAL.add(new Material.Bulk("PVC", 1390, false));
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Spruce", 450, false));
|
BULK_MATERIAL.add(new Material.Bulk("Spruce", 450, false));
|
||||||
|
// TODO: CRITICAL: Add styrofoam
|
||||||
BULK_MATERIAL.add(new Material.Bulk("Quantum tubing",1050, false));
|
BULK_MATERIAL.add(new Material.Bulk("Quantum tubing",1050, false));
|
||||||
|
|
||||||
SURFACE_MATERIAL.add(new Material.Surface("Ripstop nylon", 0.067, false));
|
SURFACE_MATERIAL.add(new Material.Surface("Ripstop nylon", 0.067, false));
|
||||||
@ -141,6 +143,14 @@ public class Databases {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used just for ensuring initialization of the class.
|
||||||
|
*/
|
||||||
|
public static void fakeMethod() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a material from the database with the specified type and name. Returns
|
* Find a material from the database with the specified type and name. Returns
|
||||||
* <code>null</code> if the specified material could not be found.
|
* <code>null</code> if the specified material could not be found.
|
||||||
|
|||||||
38
src/net/sf/openrocket/gui/components/HtmlLabel.java
Normal file
38
src/net/sf/openrocket/gui/components/HtmlLabel.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package net.sf.openrocket.gui.components;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JLabel that limits the minimum and maximum height of the label to the
|
||||||
|
* initial preferred height of the label. This is required in labels that use HTML
|
||||||
|
* since these often cause the panels to expand too much in height.
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
public class HtmlLabel extends JLabel {
|
||||||
|
|
||||||
|
public HtmlLabel() {
|
||||||
|
super();
|
||||||
|
limitSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HtmlLabel(String text) {
|
||||||
|
super(text);
|
||||||
|
limitSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HtmlLabel(String text, int horizontalAlignment) {
|
||||||
|
super(text, horizontalAlignment);
|
||||||
|
limitSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void limitSize() {
|
||||||
|
Dimension dim = this.getPreferredSize();
|
||||||
|
this.setMinimumSize(new Dimension(0, dim.height));
|
||||||
|
this.setMaximumSize(new Dimension(Integer.MAX_VALUE, dim.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package net.sf.openrocket.gui.components;
|
|
||||||
|
|
||||||
import java.awt.Font;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A resizeable JLabel. The method resizeFont(float) changes the current font size by the
|
|
||||||
* given (positive or negative) amount. The change is relative to the current font size.
|
|
||||||
* <p>
|
|
||||||
* A nice small text is achievable by <code>new ResizeLabel("My text", -2);</code>
|
|
||||||
*
|
|
||||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ResizeLabel extends JLabel {
|
|
||||||
|
|
||||||
public ResizeLabel() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResizeLabel(String text) {
|
|
||||||
super(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResizeLabel(float size) {
|
|
||||||
super();
|
|
||||||
resizeFont(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResizeLabel(String text, float size) {
|
|
||||||
super(text);
|
|
||||||
resizeFont(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResizeLabel(String text, int horizontalAlignment, float size) {
|
|
||||||
super(text, horizontalAlignment);
|
|
||||||
resizeFont(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void resizeFont(float size) {
|
|
||||||
Font font = this.getFont();
|
|
||||||
font = font.deriveFont(font.getSize2D()+size);
|
|
||||||
this.setFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
111
src/net/sf/openrocket/gui/components/StyledLabel.java
Normal file
111
src/net/sf/openrocket/gui/components/StyledLabel.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package net.sf.openrocket.gui.components;
|
||||||
|
|
||||||
|
import java.awt.Font;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resizeable and styleable JLabel. The method {@link #resizeFont(float)} changes the
|
||||||
|
* current font size by the given (positive or negative) amount. The change is relative
|
||||||
|
* to the current font size. The method {@link #setFontStyle(Style)} sets the style
|
||||||
|
* (bold/italic) of the font.
|
||||||
|
* <p>
|
||||||
|
* A nice small text is achievable by <code>new ResizeLabel("My text", -2);</code>
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class StyledLabel extends JLabel {
|
||||||
|
|
||||||
|
public enum Style {
|
||||||
|
PLAIN(Font.PLAIN),
|
||||||
|
BOLD(Font.BOLD),
|
||||||
|
ITALIC(Font.ITALIC),
|
||||||
|
BOLD_ITALIC(Font.BOLD | Font.ITALIC);
|
||||||
|
|
||||||
|
private int style;
|
||||||
|
Style(int fontStyle) {
|
||||||
|
this.style = fontStyle;
|
||||||
|
}
|
||||||
|
public int getFontStyle() {
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public StyledLabel() {
|
||||||
|
this("", SwingConstants.LEADING, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text) {
|
||||||
|
this(text, SwingConstants.LEADING, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(float size) {
|
||||||
|
this("", SwingConstants.LEADING, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text, float size) {
|
||||||
|
this(text, SwingConstants.LEADING, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text, int horizontalAlignment, float size) {
|
||||||
|
super(text, horizontalAlignment);
|
||||||
|
resizeFont(size);
|
||||||
|
checkPreferredSize(size, Style.PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public StyledLabel(Style style) {
|
||||||
|
this("", SwingConstants.LEADING, 0f, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text, Style style) {
|
||||||
|
this(text, SwingConstants.LEADING, 0f, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(float size, Style style) {
|
||||||
|
this("", SwingConstants.LEADING, size, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text, float size, Style style) {
|
||||||
|
this(text, SwingConstants.LEADING, size, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyledLabel(String text, int horizontalAlignment, float size, Style style) {
|
||||||
|
super(text, horizontalAlignment);
|
||||||
|
resizeFont(size);
|
||||||
|
setFontStyle(style);
|
||||||
|
checkPreferredSize(size, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void checkPreferredSize(float size, Style style) {
|
||||||
|
String str = this.getText();
|
||||||
|
if (str.startsWith("<html>") && str.indexOf("<br") < 0) {
|
||||||
|
StyledLabel label = new StyledLabel("plaintext", size, style);
|
||||||
|
label.validate();
|
||||||
|
System.out.println("Plain-text label: " + label.getPreferredSize());
|
||||||
|
System.out.println("HTML label: " + this.getPreferredSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void resizeFont(float size) {
|
||||||
|
Font font = this.getFont();
|
||||||
|
font = font.deriveFont(font.getSize2D()+size);
|
||||||
|
this.setFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFontStyle(Style style) {
|
||||||
|
Font font = this.getFont();
|
||||||
|
font = font.deriveFont(style.getFontStyle());
|
||||||
|
this.setFont(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ import net.sf.openrocket.unit.UnitGroup;
|
|||||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class UnitSelector extends ResizeLabel implements ChangeListener, MouseListener,
|
public class UnitSelector extends StyledLabel implements ChangeListener, MouseListener,
|
||||||
ItemSelectable {
|
ItemSelectable {
|
||||||
|
|
||||||
private DoubleModel model;
|
private DoubleModel model;
|
||||||
|
|||||||
@ -15,7 +15,9 @@ import net.sf.openrocket.gui.SpinnerEditor;
|
|||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
import net.sf.openrocket.gui.adaptors.EnumModel;
|
import net.sf.openrocket.gui.adaptors.EnumModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel.Style;
|
||||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||||
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
|
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
@ -107,7 +109,8 @@ public abstract class FinSetConfig extends RocketComponentConfig {
|
|||||||
// JPanel panel = new JPanel(new MigLayout("fillx, align 20% 20%, gap rel unrel",
|
// JPanel panel = new JPanel(new MigLayout("fillx, align 20% 20%, gap rel unrel",
|
||||||
// "[40lp][80lp::][30lp::][100lp::]",""));
|
// "[40lp][80lp::][30lp::][100lp::]",""));
|
||||||
|
|
||||||
panel.add(new JLabel("<html><b>Through-the-wall fin tabs:</b>"), "spanx, wrap 30lp");
|
panel.add(new StyledLabel("Through-the-wall fin tabs:", Style.BOLD),
|
||||||
|
"spanx, wrap 30lp");
|
||||||
|
|
||||||
JLabel label;
|
JLabel label;
|
||||||
DoubleModel m;
|
DoubleModel m;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import net.sf.openrocket.gui.adaptors.DoubleModel;
|
|||||||
import net.sf.openrocket.gui.adaptors.EnumModel;
|
import net.sf.openrocket.gui.adaptors.EnumModel;
|
||||||
import net.sf.openrocket.gui.adaptors.IntegerModel;
|
import net.sf.openrocket.gui.adaptors.IntegerModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.gui.scalefigure.FinPointFigure;
|
import net.sf.openrocket.gui.scalefigure.FinPointFigure;
|
||||||
import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
|
import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
|
||||||
@ -212,14 +212,14 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
panel.add(tablePane,"growy, width 100lp:100lp:, height 100lp:250lp:");
|
panel.add(tablePane,"growy, width 100lp:100lp:, height 100lp:250lp:");
|
||||||
panel.add(figurePane,"gap unrel, spanx, growx, growy 1000, height 100lp:250lp:, wrap");
|
panel.add(figurePane,"gap unrel, spanx, growx, growy 1000, height 100lp:250lp:, wrap");
|
||||||
|
|
||||||
panel.add(new ResizeLabel("Double-click", -2), "alignx 50%");
|
panel.add(new StyledLabel("Double-click", -2), "alignx 50%");
|
||||||
|
|
||||||
panel.add(new ScaleSelector(figurePane),"spany 2");
|
panel.add(new ScaleSelector(figurePane),"spany 2");
|
||||||
panel.add(new ResizeLabel("Click+drag: Add and move points " +
|
panel.add(new StyledLabel("Click+drag: Add and move points " +
|
||||||
"Ctrl+click: Remove point", -2), "spany 2, right, wrap");
|
"Ctrl+click: Remove point", -2), "spany 2, right, wrap");
|
||||||
|
|
||||||
|
|
||||||
panel.add(new ResizeLabel("to edit", -2), "alignx 50%");
|
panel.add(new StyledLabel("to edit", -2), "alignx 50%");
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,10 @@ import net.sf.openrocket.gui.adaptors.EnumModel;
|
|||||||
import net.sf.openrocket.gui.adaptors.IntegerModel;
|
import net.sf.openrocket.gui.adaptors.IntegerModel;
|
||||||
import net.sf.openrocket.gui.adaptors.MaterialModel;
|
import net.sf.openrocket.gui.adaptors.MaterialModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
|
import net.sf.openrocket.gui.components.HtmlLabel;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel.Style;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
import net.sf.openrocket.rocketcomponent.MassComponent;
|
import net.sf.openrocket.rocketcomponent.MassComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.Parachute;
|
import net.sf.openrocket.rocketcomponent.Parachute;
|
||||||
@ -36,7 +39,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
|
|||||||
|
|
||||||
|
|
||||||
//// Canopy
|
//// Canopy
|
||||||
panel.add(new JLabel("<html><b>Canopy:</b>"), "wrap unrel");
|
panel.add(new StyledLabel("Canopy:", Style.BOLD), "wrap unrel");
|
||||||
|
|
||||||
|
|
||||||
panel.add(new JLabel("Diameter:"));
|
panel.add(new JLabel("Diameter:"));
|
||||||
@ -62,7 +65,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
|
|||||||
|
|
||||||
|
|
||||||
// CD
|
// CD
|
||||||
JLabel label = new JLabel("<html>Drag coefficient C<sub>D</sub>:");
|
JLabel label = new HtmlLabel("<html>Drag coefficient C<sub>D</sub>:");
|
||||||
String tip = "<html>The drag coefficient relative to the total area of the parachute.<br>" +
|
String tip = "<html>The drag coefficient relative to the total area of the parachute.<br>" +
|
||||||
"A larger drag coefficient yields a slowed descent rate. " +
|
"A larger drag coefficient yields a slowed descent rate. " +
|
||||||
"A typical value for parachutes is 0.8.";
|
"A typical value for parachutes is 0.8.";
|
||||||
@ -89,7 +92,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
|
|||||||
|
|
||||||
|
|
||||||
//// Shroud lines
|
//// Shroud lines
|
||||||
panel.add(new JLabel("<html><b>Shroud lines:</b>"), "wrap unrel");
|
panel.add(new StyledLabel("Shroud lines:", Style.BOLD), "wrap unrel");
|
||||||
|
|
||||||
|
|
||||||
panel.add(new JLabel("Number of lines:"));
|
panel.add(new JLabel("Number of lines:"));
|
||||||
|
|||||||
@ -17,7 +17,8 @@ import net.sf.openrocket.gui.adaptors.DoubleModel;
|
|||||||
import net.sf.openrocket.gui.adaptors.EnumModel;
|
import net.sf.openrocket.gui.adaptors.EnumModel;
|
||||||
import net.sf.openrocket.gui.adaptors.MaterialModel;
|
import net.sf.openrocket.gui.adaptors.MaterialModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.HtmlLabel;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
import net.sf.openrocket.rocketcomponent.MassComponent;
|
import net.sf.openrocket.rocketcomponent.MassComponent;
|
||||||
@ -93,7 +94,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
|
|||||||
|
|
||||||
|
|
||||||
// CD
|
// CD
|
||||||
JLabel label = new JLabel("<html>Drag coefficient C<sub>D</sub>:");
|
JLabel label = new HtmlLabel("<html>Drag coefficient C<sub>D</sub>:");
|
||||||
String tip = "<html>The drag coefficient relative to the total area of the streamer.<br>" +
|
String tip = "<html>The drag coefficient relative to the total area of the streamer.<br>" +
|
||||||
"A larger drag coefficient yields a slowed descent rate.";
|
"A larger drag coefficient yields a slowed descent rate.";
|
||||||
label.setToolTipText(tip);
|
label.setToolTipText(tip);
|
||||||
@ -110,7 +111,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
|
|||||||
check.setText("Automatic");
|
check.setText("Automatic");
|
||||||
panel.add(check,"skip, span, wrap");
|
panel.add(check,"skip, span, wrap");
|
||||||
|
|
||||||
panel.add(new ResizeLabel("The drag coefficient is relative to the area of the streamer.",
|
panel.add(new StyledLabel("The drag coefficient is relative to the area of the streamer.",
|
||||||
-2), "span, wrap");
|
-2), "span, wrap");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import javax.swing.JLabel;
|
|||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.URLLabel;
|
import net.sf.openrocket.gui.components.URLLabel;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
import net.sf.openrocket.util.Icons;
|
import net.sf.openrocket.util.Icons;
|
||||||
@ -31,18 +31,18 @@ public class AboutDialog extends JDialog {
|
|||||||
panel.add(new JLabel(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket")),
|
panel.add(new JLabel(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket")),
|
||||||
"spany 5, top");
|
"spany 5, top");
|
||||||
|
|
||||||
panel.add(new ResizeLabel("OpenRocket", 20), "ax 50%, growy, wrap para");
|
panel.add(new StyledLabel("OpenRocket", 20), "ax 50%, growy, wrap para");
|
||||||
panel.add(new ResizeLabel("Version " + version, 3), "ax 50%, growy, wrap rel");
|
panel.add(new StyledLabel("Version " + version, 3), "ax 50%, growy, wrap rel");
|
||||||
|
|
||||||
String source = Prefs.getBuildSource();
|
String source = Prefs.getBuildSource();
|
||||||
if (!Prefs.DEFAULT_BUILD_SOURCE.equalsIgnoreCase(source)) {
|
if (!Prefs.DEFAULT_BUILD_SOURCE.equalsIgnoreCase(source)) {
|
||||||
panel.add(new ResizeLabel("Distributed by " + source, -1),
|
panel.add(new StyledLabel("Distributed by " + source, -1),
|
||||||
"ax 50%, growy, wrap para");
|
"ax 50%, growy, wrap para");
|
||||||
} else {
|
} else {
|
||||||
panel.add(new ResizeLabel(" ", -1), "ax 50%, growy, wrap para");
|
panel.add(new StyledLabel(" ", -1), "ax 50%, growy, wrap para");
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.add(new ResizeLabel("Copyright \u00A9 2007-2009 Sampo Niskanen"),
|
panel.add(new StyledLabel("Copyright \u00A9 2007-2009 Sampo Niskanen"),
|
||||||
"ax 50%, growy, wrap para");
|
"ax 50%, growy, wrap para");
|
||||||
|
|
||||||
panel.add(new URLLabel(OPENROCKET_URL), "ax 50%, growy, wrap para");
|
panel.add(new URLLabel(OPENROCKET_URL), "ax 50%, growy, wrap para");
|
||||||
|
|||||||
@ -25,8 +25,8 @@ import javax.swing.JScrollPane;
|
|||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.communication.Communication;
|
import net.sf.openrocket.communication.BugReporter;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.SelectableLabel;
|
import net.sf.openrocket.gui.components.SelectableLabel;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
import net.sf.openrocket.util.JarUtil;
|
import net.sf.openrocket.util.JarUtil;
|
||||||
@ -66,7 +66,7 @@ public class BugReportDialog extends JDialog {
|
|||||||
panel.add(new JScrollPane(textArea), "grow, wrap");
|
panel.add(new JScrollPane(textArea), "grow, wrap");
|
||||||
|
|
||||||
|
|
||||||
panel.add(new ResizeLabel("The information above may be included in a public " +
|
panel.add(new StyledLabel("The information above may be included in a public " +
|
||||||
"bug report. Make sure it does not contain any sensitive information you " +
|
"bug report. Make sure it does not contain any sensitive information you " +
|
||||||
"do not want to be made public.", -1), "wrap para");
|
"do not want to be made public.", -1), "wrap para");
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ public class BugReportDialog extends JDialog {
|
|||||||
String text = textArea.getText();
|
String text = textArea.getText();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Communication.sendBugReport(text);
|
BugReporter.sendBugReport(text);
|
||||||
|
|
||||||
// Success if we came here
|
// Success if we came here
|
||||||
JOptionPane.showMessageDialog(BugReportDialog.this,
|
JOptionPane.showMessageDialog(BugReportDialog.this,
|
||||||
|
|||||||
@ -45,7 +45,7 @@ import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
|||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
|
import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.StageSelector;
|
import net.sf.openrocket.gui.components.StageSelector;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
||||||
@ -370,14 +370,14 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
panel.add(new ResizeLabel("Reference length: ", -1),
|
panel.add(new StyledLabel("Reference length: ", -1),
|
||||||
"span, split, gapleft para, gapright rel");
|
"span, split, gapleft para, gapright rel");
|
||||||
DoubleModel dm = new DoubleModel(conditions, "RefLength", UnitGroup.UNITS_LENGTH);
|
DoubleModel dm = new DoubleModel(conditions, "RefLength", UnitGroup.UNITS_LENGTH);
|
||||||
UnitSelector sel = new UnitSelector(dm, true);
|
UnitSelector sel = new UnitSelector(dm, true);
|
||||||
sel.resizeFont(-1);
|
sel.resizeFont(-1);
|
||||||
panel.add(sel, "gapright para");
|
panel.add(sel, "gapright para");
|
||||||
|
|
||||||
panel.add(new ResizeLabel("Reference area: ", -1), "gapright rel");
|
panel.add(new StyledLabel("Reference area: ", -1), "gapright rel");
|
||||||
dm = new DoubleModel(conditions, "RefArea", UnitGroup.UNITS_AREA);
|
dm = new DoubleModel(conditions, "RefArea", UnitGroup.UNITS_AREA);
|
||||||
sel = new UnitSelector(dm, true);
|
sel = new UnitSelector(dm, true);
|
||||||
sel.resizeFont(-1);
|
sel.resizeFont(-1);
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import javax.swing.JTextField;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
@ -54,7 +54,7 @@ public class CustomMaterialDialog extends JDialog {
|
|||||||
"gapleft para, span, wrap" + (note == null ? " para":""));
|
"gapleft para, span, wrap" + (note == null ? " para":""));
|
||||||
}
|
}
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
panel.add(new ResizeLabel(note, -1), "span, wrap para");
|
panel.add(new StyledLabel(note, -1), "span, wrap para");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import javax.swing.JScrollPane;
|
|||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
|
|
||||||
public class LicenseDialog extends JDialog {
|
public class LicenseDialog extends JDialog {
|
||||||
@ -32,7 +32,7 @@ public class LicenseDialog extends JDialog {
|
|||||||
|
|
||||||
JPanel panel = new JPanel(new MigLayout("fill"));
|
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||||
|
|
||||||
panel.add(new ResizeLabel("OpenRocket license", 10), "ax 50%, wrap para");
|
panel.add(new StyledLabel("OpenRocket license", 10), "ax 50%, wrap para");
|
||||||
|
|
||||||
String licenseText;
|
String licenseText;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import javax.swing.table.TableRowSorter;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.database.Databases;
|
import net.sf.openrocket.database.Databases;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.motor.Motor;
|
import net.sf.openrocket.motor.Motor;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
@ -251,7 +251,7 @@ public class MotorChooserDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
panel.add(delayBox,"gapright unrel");
|
panel.add(delayBox,"gapright unrel");
|
||||||
panel.add(new ResizeLabel("(Number of seconds or \"None\")", -1), "wrap para");
|
panel.add(new StyledLabel("(Number of seconds or \"None\")", -1), "wrap para");
|
||||||
setDelays(false);
|
setDelays(false);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
73
src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
Normal file
73
src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package net.sf.openrocket.gui.dialogs;
|
||||||
|
|
||||||
|
import java.awt.Window;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
import net.sf.openrocket.communication.UpdateInfo;
|
||||||
|
import net.sf.openrocket.gui.components.URLLabel;
|
||||||
|
import net.sf.openrocket.util.ComparablePair;
|
||||||
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
|
import net.sf.openrocket.util.Icons;
|
||||||
|
|
||||||
|
public class UpdateInfoDialog extends JDialog {
|
||||||
|
|
||||||
|
public UpdateInfoDialog(UpdateInfo info) {
|
||||||
|
super((Window)null, "OpenRocket update available", ModalityType.APPLICATION_MODAL);
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||||
|
|
||||||
|
|
||||||
|
panel.add(new JLabel(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket")),
|
||||||
|
"spany 100, top");
|
||||||
|
|
||||||
|
|
||||||
|
panel.add(new JLabel("<html><b>OpenRocket version " + info.getLatestVersion() +
|
||||||
|
" is available!"), "wrap para");
|
||||||
|
|
||||||
|
List<ComparablePair<Integer, String>> updates = info.getUpdates();
|
||||||
|
if (updates.size() > 0) {
|
||||||
|
panel.add(new JLabel("Updates include:"), "wrap rel");
|
||||||
|
|
||||||
|
Collections.sort(updates);
|
||||||
|
int count = 0;
|
||||||
|
int n = -1;
|
||||||
|
for (int i=updates.size()-1; i>=0; i--) {
|
||||||
|
// Add only specific number of top features
|
||||||
|
if (count >= 4 && n != updates.get(i).getU())
|
||||||
|
break;
|
||||||
|
n = updates.get(i).getU();
|
||||||
|
panel.add(new JLabel(" \u2022 " + updates.get(i).getV()), "wrap 0px");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.add(new JLabel("Download the new version from:"),
|
||||||
|
"gaptop para, alignx 50%, wrap unrel");
|
||||||
|
panel.add(new URLLabel(AboutDialog.OPENROCKET_URL), "alignx 50%, wrap para");
|
||||||
|
|
||||||
|
JButton button = new JButton("Close");
|
||||||
|
button.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
UpdateInfoDialog.this.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
panel.add(button, "right");
|
||||||
|
|
||||||
|
this.add(panel);
|
||||||
|
|
||||||
|
this.pack();
|
||||||
|
this.setLocationRelativeTo(null);
|
||||||
|
GUIUtil.setDisposableDialogOptions(this, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.JTabbedPane;
|
import javax.swing.JTabbedPane;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.unit.Unit;
|
import net.sf.openrocket.unit.Unit;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.GUIUtil;
|
import net.sf.openrocket.util.GUIUtil;
|
||||||
@ -204,7 +204,7 @@ public class PreferencesDialog extends JDialog {
|
|||||||
panel.add(button, "grow, wrap para");
|
panel.add(button, "grow, wrap para");
|
||||||
|
|
||||||
|
|
||||||
panel.add(new ResizeLabel("The effects will take place the next time you open a window.",-2),
|
panel.add(new StyledLabel("The effects will take place the next time you open a window.",-2),
|
||||||
"spanx, wrap");
|
"spanx, wrap");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,7 @@ import javax.swing.ListSelectionModel;
|
|||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.Timer;
|
||||||
import javax.swing.ToolTipManager;
|
import javax.swing.ToolTipManager;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.TitledBorder;
|
import javax.swing.border.TitledBorder;
|
||||||
@ -60,6 +61,9 @@ import javax.swing.tree.TreeSelectionModel;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
|
import net.sf.openrocket.communication.UpdateInfo;
|
||||||
|
import net.sf.openrocket.communication.UpdateInfoRetriever;
|
||||||
|
import net.sf.openrocket.database.Databases;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
import net.sf.openrocket.file.GeneralRocketLoader;
|
import net.sf.openrocket.file.GeneralRocketLoader;
|
||||||
import net.sf.openrocket.file.OpenRocketSaver;
|
import net.sf.openrocket.file.OpenRocketSaver;
|
||||||
@ -74,6 +78,7 @@ import net.sf.openrocket.gui.dialogs.ComponentAnalysisDialog;
|
|||||||
import net.sf.openrocket.gui.dialogs.ExampleDesignDialog;
|
import net.sf.openrocket.gui.dialogs.ExampleDesignDialog;
|
||||||
import net.sf.openrocket.gui.dialogs.LicenseDialog;
|
import net.sf.openrocket.gui.dialogs.LicenseDialog;
|
||||||
import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
|
import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
|
||||||
|
import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
|
||||||
import net.sf.openrocket.gui.dialogs.WarningDialog;
|
import net.sf.openrocket.gui.dialogs.WarningDialog;
|
||||||
import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
|
import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
|
||||||
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
||||||
@ -1151,7 +1156,18 @@ public class BasicFrame extends JFrame {
|
|||||||
|
|
||||||
|
|
||||||
private static void runMain(String[] args) {
|
private static void runMain(String[] args) {
|
||||||
|
|
||||||
|
// Start update info fetching
|
||||||
|
final UpdateInfoRetriever updateInfo;
|
||||||
|
if (Prefs.getCheckUpdates()) {
|
||||||
|
updateInfo = new UpdateInfoRetriever();
|
||||||
|
updateInfo.start();
|
||||||
|
} else {
|
||||||
|
updateInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the look-and-feel. On Linux, Motif/Metal is sometimes incorrectly used
|
* Set the look-and-feel. On Linux, Motif/Metal is sometimes incorrectly used
|
||||||
* which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
|
* which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
|
||||||
@ -1200,12 +1216,51 @@ public class BasicFrame extends JFrame {
|
|||||||
|
|
||||||
// Load defaults
|
// Load defaults
|
||||||
Prefs.loadDefaultUnits();
|
Prefs.loadDefaultUnits();
|
||||||
|
|
||||||
|
|
||||||
// Starting action
|
|
||||||
|
// Load motors etc.
|
||||||
|
Databases.fakeMethod();
|
||||||
|
|
||||||
|
// Starting action (load files or open new document)
|
||||||
if (!handleCommandLine(args)) {
|
if (!handleCommandLine(args)) {
|
||||||
newAction();
|
newAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check whether update info has been fetched or whether it needs more time
|
||||||
|
checkUpdateStatus(updateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
|
||||||
|
if (updateInfo == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int delay = 1000;
|
||||||
|
if (!updateInfo.isRunning())
|
||||||
|
delay = 100;
|
||||||
|
|
||||||
|
final Timer timer = new Timer(delay, null);
|
||||||
|
|
||||||
|
ActionListener listener = new ActionListener() {
|
||||||
|
private int count = 5;
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (!updateInfo.isRunning()) {
|
||||||
|
timer.stop();
|
||||||
|
|
||||||
|
UpdateInfo info = updateInfo.getUpdateInfo();
|
||||||
|
if (info != null && !Prefs.getVersion().equals(info.getLatestVersion())) {
|
||||||
|
new UpdateInfoDialog(info).setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
if (count <= 0)
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.addActionListener(listener);
|
||||||
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import javax.swing.tree.TreeSelectionModel;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
|
import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
|
||||||
import net.sf.openrocket.rocketcomponent.BodyComponent;
|
import net.sf.openrocket.rocketcomponent.BodyComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||||
@ -269,7 +269,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
|
|||||||
// Add labels
|
// Add labels
|
||||||
String[] l = text.split("\n");
|
String[] l = text.split("\n");
|
||||||
for (int i=0; i<l.length; i++) {
|
for (int i=0; i<l.length; i++) {
|
||||||
add(new ResizeLabel(l[i],SwingConstants.CENTER,-3.0f),"growx");
|
add(new StyledLabel(l[i],SwingConstants.CENTER,-3.0f),"growx");
|
||||||
}
|
}
|
||||||
|
|
||||||
add(new JLabel(),"push, sizegroup spacing");
|
add(new JLabel(),"push, sizegroup spacing");
|
||||||
@ -502,7 +502,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
|
|||||||
JPanel panel = new JPanel(new MigLayout());
|
JPanel panel = new JPanel(new MigLayout());
|
||||||
JCheckBox check = new JCheckBox("Do not ask me again");
|
JCheckBox check = new JCheckBox("Do not ask me again");
|
||||||
panel.add(check,"wrap");
|
panel.add(check,"wrap");
|
||||||
panel.add(new ResizeLabel("You can change the default operation in the " +
|
panel.add(new StyledLabel("You can change the default operation in the " +
|
||||||
"preferences.",-2));
|
"preferences.",-2));
|
||||||
|
|
||||||
int sel = JOptionPane.showOptionDialog(null, // parent component
|
int sel = JOptionPane.showOptionDialog(null, // parent component
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import javax.swing.KeyStroke;
|
|||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
|
import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
|
||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||||
@ -209,7 +209,7 @@ public class RocketActions {
|
|||||||
JPanel panel = new JPanel(new MigLayout());
|
JPanel panel = new JPanel(new MigLayout());
|
||||||
JCheckBox dontAsk = new JCheckBox("Do not ask me again");
|
JCheckBox dontAsk = new JCheckBox("Do not ask me again");
|
||||||
panel.add(dontAsk,"wrap");
|
panel.add(dontAsk,"wrap");
|
||||||
panel.add(new ResizeLabel("You can change the default operation in the " +
|
panel.add(new StyledLabel("You can change the default operation in the " +
|
||||||
"preferences.",-2));
|
"preferences.",-2));
|
||||||
|
|
||||||
int ret = JOptionPane.showConfirmDialog(
|
int ret = JOptionPane.showConfirmDialog(
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import net.sf.openrocket.document.events.DocumentChangeListener;
|
|||||||
import net.sf.openrocket.document.events.SimulationChangeEvent;
|
import net.sf.openrocket.document.events.SimulationChangeEvent;
|
||||||
import net.sf.openrocket.gui.adaptors.Column;
|
import net.sf.openrocket.gui.adaptors.Column;
|
||||||
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
@ -146,7 +146,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
JPanel panel = new JPanel(new MigLayout());
|
JPanel panel = new JPanel(new MigLayout());
|
||||||
JCheckBox dontAsk = new JCheckBox("Do not ask me again");
|
JCheckBox dontAsk = new JCheckBox("Do not ask me again");
|
||||||
panel.add(dontAsk,"wrap");
|
panel.add(dontAsk,"wrap");
|
||||||
panel.add(new ResizeLabel("You can change the default operation in the " +
|
panel.add(new StyledLabel("You can change the default operation in the " +
|
||||||
"preferences.",-2));
|
"preferences.",-2));
|
||||||
|
|
||||||
int ret = JOptionPane.showConfirmDialog(SimulationPanel.this,
|
int ret = JOptionPane.showConfirmDialog(SimulationPanel.this,
|
||||||
@ -215,7 +215,7 @@ public class SimulationPanel extends JPanel {
|
|||||||
|
|
||||||
// Initialize the label
|
// Initialize the label
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
label = new ResizeLabel(2f);
|
label = new StyledLabel(2f);
|
||||||
label.setIconTextGap(1);
|
label.setIconTextGap(1);
|
||||||
// label.setFont(label.getFont().deriveFont(Font.BOLD));
|
// label.setFont(label.getFont().deriveFont(Font.BOLD));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import javax.swing.table.TableColumnModel;
|
|||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.gui.components.ResizeLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
import net.sf.openrocket.simulation.FlightEvent;
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
@ -160,7 +160,7 @@ public class PlotPanel extends JPanel {
|
|||||||
this.add(domainUnitSelector, "width 40lp, gapright para");
|
this.add(domainUnitSelector, "width 40lp, gapright para");
|
||||||
|
|
||||||
|
|
||||||
ResizeLabel desc = new ResizeLabel("<html><p>The data will be plotted in time order " +
|
StyledLabel desc = new StyledLabel("<html><p>The data will be plotted in time order " +
|
||||||
"even if the X axis type is not time.", -2);
|
"even if the X axis type is not time.", -2);
|
||||||
this.add(desc, "width :0px:, growx, wrap para");
|
this.add(desc, "width :0px:, growx, wrap para");
|
||||||
|
|
||||||
|
|||||||
83
src/net/sf/openrocket/util/LimitedInputStream.java
Normal file
83
src/net/sf/openrocket/util/LimitedInputStream.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package net.sf.openrocket.util;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filtering InputStream that limits the number of bytes that can be
|
||||||
|
* read from a stream. This can be used to enforce security, so that overlong
|
||||||
|
* input is ignored.
|
||||||
|
*
|
||||||
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
|
*/
|
||||||
|
public class LimitedInputStream extends FilterInputStream {
|
||||||
|
|
||||||
|
private int remaining;
|
||||||
|
|
||||||
|
public LimitedInputStream(InputStream is, int limit) {
|
||||||
|
super(is);
|
||||||
|
this.remaining = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int available() throws IOException {
|
||||||
|
int available = super.available();
|
||||||
|
return Math.min(available, remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
if (remaining <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int result = super.read(b, off, Math.min(len, remaining));
|
||||||
|
if (result >= 0)
|
||||||
|
remaining -= result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
if (n > remaining)
|
||||||
|
n = remaining;
|
||||||
|
long result = super.skip(n);
|
||||||
|
remaining -= result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (remaining <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int result = super.read();
|
||||||
|
if (result >= 0)
|
||||||
|
remaining--;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Disable mark support
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mark(int readlimit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void reset() throws IOException {
|
||||||
|
throw new IOException("mark/reset not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -57,6 +57,7 @@ public class Prefs {
|
|||||||
private static final String BUILD_VERSION;
|
private static final String BUILD_VERSION;
|
||||||
private static final String BUILD_SOURCE;
|
private static final String BUILD_SOURCE;
|
||||||
public static final String DEFAULT_BUILD_SOURCE = "default";
|
public static final String DEFAULT_BUILD_SOURCE = "default";
|
||||||
|
private static final boolean DEFAULT_CHECK_UPDATES;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
@ -81,6 +82,12 @@ public class Prefs {
|
|||||||
|
|
||||||
BUILD_SOURCE = props.getProperty("build.source");
|
BUILD_SOURCE = props.getProperty("build.source");
|
||||||
|
|
||||||
|
String value = props.getProperty("build.checkupdates");
|
||||||
|
if (value != null)
|
||||||
|
DEFAULT_CHECK_UPDATES = Boolean.parseBoolean(value);
|
||||||
|
else
|
||||||
|
DEFAULT_CHECK_UPDATES = true;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new MissingResourceException(
|
throw new MissingResourceException(
|
||||||
"Error reading build.properties",
|
"Error reading build.properties",
|
||||||
@ -103,6 +110,8 @@ public class Prefs {
|
|||||||
|
|
||||||
public static final String PLOT_SHOW_POINTS = "ShowPlotPoints";
|
public static final String PLOT_SHOW_POINTS = "ShowPlotPoints";
|
||||||
|
|
||||||
|
private static final String CHECK_UPDATES = "CheckUpdates";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node to this application's preferences.
|
* Node to this application's preferences.
|
||||||
* @deprecated Use the static methods instead.
|
* @deprecated Use the static methods instead.
|
||||||
@ -152,14 +161,18 @@ public class Prefs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final Material DEFAULT_LINE_MATERIAL =
|
/*
|
||||||
Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2mm, 1/16 in)",
|
* Within a holder class so they will load only when needed.
|
||||||
0.0018, false);
|
*/
|
||||||
private static final Material DEFAULT_SURFACE_MATERIAL =
|
private static class DefaultMaterialHolder {
|
||||||
Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon", 0.067, false);
|
private static final Material DEFAULT_LINE_MATERIAL =
|
||||||
private static final Material DEFAULT_BULK_MATERIAL =
|
Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2mm, 1/16 in)",
|
||||||
Databases.findMaterial(Material.Type.BULK, "Cardboard", 680, false);
|
0.0018, false);
|
||||||
|
private static final Material DEFAULT_SURFACE_MATERIAL =
|
||||||
|
Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon", 0.067, false);
|
||||||
|
private static final Material DEFAULT_BULK_MATERIAL =
|
||||||
|
Databases.findMaterial(Material.Type.BULK, "Cardboard", 680, false);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
|
|
||||||
@ -242,6 +255,16 @@ public class Prefs {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean getCheckUpdates() {
|
||||||
|
return PREFNODE.getBoolean(CHECK_UPDATES, DEFAULT_CHECK_UPDATES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCheckUpdates(boolean check) {
|
||||||
|
PREFNODE.putBoolean(CHECK_UPDATES, check);
|
||||||
|
storeVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
public static File getDefaultDirectory() {
|
public static File getDefaultDirectory() {
|
||||||
@ -360,11 +383,11 @@ public class Prefs {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LINE:
|
case LINE:
|
||||||
return DEFAULT_LINE_MATERIAL;
|
return DefaultMaterialHolder.DEFAULT_LINE_MATERIAL;
|
||||||
case SURFACE:
|
case SURFACE:
|
||||||
return DEFAULT_SURFACE_MATERIAL;
|
return DefaultMaterialHolder.DEFAULT_SURFACE_MATERIAL;
|
||||||
case BULK:
|
case BULK:
|
||||||
return DEFAULT_BULK_MATERIAL;
|
return DefaultMaterialHolder.DEFAULT_BULK_MATERIAL;
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unknown material type: "+type);
|
throw new IllegalArgumentException("Unknown material type: "+type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,17 +14,24 @@ import net.sf.openrocket.motor.ThrustCurveMotor;
|
|||||||
|
|
||||||
public class MotorCompare {
|
public class MotorCompare {
|
||||||
|
|
||||||
|
/** Maximum allowed difference in maximum thrust */
|
||||||
private static final double MAX_THRUST_MARGIN = 0.20;
|
private static final double MAX_THRUST_MARGIN = 0.20;
|
||||||
|
/** Maximum allowed difference in total impulse */
|
||||||
private static final double TOTAL_IMPULSE_MARGIN = 0.10;
|
private static final double TOTAL_IMPULSE_MARGIN = 0.10;
|
||||||
|
/** Maximum allowed difference in mass values */
|
||||||
private static final double MASS_MARGIN = 0.10;
|
private static final double MASS_MARGIN = 0.10;
|
||||||
|
|
||||||
private static final double THRUST_MARGIN = 0.15;
|
/** Number of time points in thrust curve to compare */
|
||||||
|
|
||||||
private static final int DIVISIONS = 100;
|
private static final int DIVISIONS = 100;
|
||||||
|
/** Maximum difference in thrust for a time point to be considered invalid */
|
||||||
|
private static final double THRUST_MARGIN = 0.15;
|
||||||
|
/** Number of invalid time points allowed */
|
||||||
private static final int ALLOWED_INVALID_POINTS = 15;
|
private static final int ALLOWED_INVALID_POINTS = 15;
|
||||||
|
|
||||||
|
/** Minimum number of thrust curve points allowed (incl. start and end points) */
|
||||||
private static final int MIN_POINTS = 7;
|
private static final int MIN_POINTS = 7;
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
final double maxThrust;
|
final double maxThrust;
|
||||||
final double maxTime;
|
final double maxTime;
|
||||||
|
|||||||
72
test/net/sf/openrocket/communication/BugReportTest.java
Normal file
72
test/net/sf/openrocket/communication/BugReportTest.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import net.sf.openrocket.util.Prefs;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
public class BugReportTest {
|
||||||
|
|
||||||
|
private HttpURLConnectionMock setup() {
|
||||||
|
HttpURLConnectionMock connection = new HttpURLConnectionMock();
|
||||||
|
Communicator.setConnectionSource(new ConnectionSourceStub(connection));
|
||||||
|
|
||||||
|
connection.setUseCaches(true);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(HttpURLConnectionMock connection) {
|
||||||
|
assertEquals(Communicator.BUG_REPORT_URL, connection.getTrueUrl());
|
||||||
|
assertTrue(connection.getConnectTimeout() > 0);
|
||||||
|
assertEquals(Prefs.getVersion(), connection.getRequestProperty("X-OpenRocket-Version"));
|
||||||
|
assertTrue(connection.getInstanceFollowRedirects());
|
||||||
|
assertEquals("POST", connection.getRequestMethod());
|
||||||
|
assertFalse(connection.getUseCaches());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBugReportSuccess() throws IOException {
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.BUG_REPORT_RESPONSE_CODE);
|
||||||
|
|
||||||
|
String message =
|
||||||
|
"MyMessage\n"+
|
||||||
|
"is important\n"+
|
||||||
|
"h\u00e4h?";
|
||||||
|
|
||||||
|
BugReporter.sendBugReport(message);
|
||||||
|
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
String msg = connection.getOutputStreamString();
|
||||||
|
assertTrue(msg.indexOf("version=" + Prefs.getVersion()) >= 0);
|
||||||
|
assertTrue(msg.indexOf(Communicator.encode(message)) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBugReportFailure() throws IOException {
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(200);
|
||||||
|
|
||||||
|
String message =
|
||||||
|
"MyMessage\n"+
|
||||||
|
"is important\n"+
|
||||||
|
"h\u00e4h?";
|
||||||
|
|
||||||
|
try {
|
||||||
|
BugReporter.sendBugReport(message);
|
||||||
|
fail("Exception did not occur");
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Success
|
||||||
|
}
|
||||||
|
|
||||||
|
check(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,120 +0,0 @@
|
|||||||
package net.sf.openrocket.communication;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class CommunicationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIllegalInputUpdateParsing() throws IOException {
|
|
||||||
|
|
||||||
UpdateInfo info;
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader(""));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("vj\u00e4avdsads"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("\u0000\u0001\u0002"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2pre"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2.x"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("\u0000\u0001\u0002"));
|
|
||||||
assertNull(info);
|
|
||||||
|
|
||||||
// Feed random bad input
|
|
||||||
Random rnd = new Random();
|
|
||||||
StringBuilder sb = new StringBuilder(10000);
|
|
||||||
for (int i=0; i<100; i++) {
|
|
||||||
int length = rnd.nextInt(10000);
|
|
||||||
sb.delete(0, sb.length());
|
|
||||||
for (int j=0; j<length; j++) {
|
|
||||||
sb.append((char)rnd.nextInt());
|
|
||||||
}
|
|
||||||
info = Communication.parseUpdateInput(new StringReader(sb.toString()));
|
|
||||||
assertNull(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidInputUpdateParsing() throws IOException {
|
|
||||||
|
|
||||||
UpdateInfo info;
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2.3"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3", info.getLatestVersion());
|
|
||||||
assertEquals(0, info.getUpdates().size());
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2.3pre"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3pre", info.getLatestVersion());
|
|
||||||
assertEquals(0, info.getUpdates().size());
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2.3-build-3"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3-build-3", info.getLatestVersion());
|
|
||||||
assertEquals(0, info.getUpdates().size());
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version: 1.2.3x\n\n"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3x", info.getLatestVersion());
|
|
||||||
assertEquals(0, info.getUpdates().size());
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader("Version:1.2.3\nfdsacd\u00e4fdsa"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3", info.getLatestVersion());
|
|
||||||
assertEquals(0, info.getUpdates().size());
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader(
|
|
||||||
"Version: 1.2.3 \n" +
|
|
||||||
"15: Fifteen\n" +
|
|
||||||
"3: Three1 \r\n" +
|
|
||||||
"3: Three2\r" +
|
|
||||||
"1:One"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3", info.getLatestVersion());
|
|
||||||
assertEquals(4, info.getUpdates().size());
|
|
||||||
assertEquals(15, info.getUpdates().get(0).getU());
|
|
||||||
assertEquals(3, info.getUpdates().get(1).getU());
|
|
||||||
assertEquals(3, info.getUpdates().get(2).getU());
|
|
||||||
assertEquals(1, info.getUpdates().get(3).getU());
|
|
||||||
assertEquals("Fifteen", info.getUpdates().get(0).getV());
|
|
||||||
assertEquals("Three1", info.getUpdates().get(1).getV());
|
|
||||||
assertEquals("Three2", info.getUpdates().get(2).getV());
|
|
||||||
assertEquals("One", info.getUpdates().get(3).getV());
|
|
||||||
|
|
||||||
|
|
||||||
info = Communication.parseUpdateInput(new StringReader(
|
|
||||||
"Version: 1.2.3\n" +
|
|
||||||
"15: (C) 1234 A&B %23 \\o/ \r\r\n" +
|
|
||||||
"5: m\u00e4c\n" +
|
|
||||||
"3: Invalid\u0000value\n" +
|
|
||||||
"1: One\u0019two"));
|
|
||||||
assertNotNull(info);
|
|
||||||
assertEquals("1.2.3", info.getLatestVersion());
|
|
||||||
assertEquals(1, info.getUpdates().size());
|
|
||||||
assertEquals(15, info.getUpdates().get(0).getU());
|
|
||||||
assertEquals("(C) 1234 A&B %23 \\o/", info.getUpdates().get(0).getV());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
public class ConnectionSourceStub implements ConnectionSource {
|
||||||
|
|
||||||
|
private final HttpURLConnection connection;
|
||||||
|
|
||||||
|
public ConnectionSourceStub(HttpURLConnection connection) {
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpURLConnection getConnection(String url) throws IOException {
|
||||||
|
if (connection instanceof HttpURLConnectionMock) {
|
||||||
|
((HttpURLConnectionMock)connection).setTrueUrl(url);
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
548
test/net/sf/openrocket/communication/HttpURLConnectionMock.java
Normal file
548
test/net/sf/openrocket/communication/HttpURLConnectionMock.java
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.ProtocolException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.Permission;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HttpURLConnectionMock extends HttpURLConnection {
|
||||||
|
|
||||||
|
private static final URL MOCK_URL;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
MOCK_URL = new URL("http://localhost/");
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile boolean instanceFollowRedirects = false;
|
||||||
|
private volatile String requestMethod = "";
|
||||||
|
private volatile int responseCode;
|
||||||
|
private Map<String, String> requestProperties = new HashMap<String, String>();
|
||||||
|
private volatile int connectTimeout = -1;
|
||||||
|
private volatile String contentEncoding = "";
|
||||||
|
|
||||||
|
private volatile boolean doInput = false;
|
||||||
|
private volatile boolean doOutput = false;
|
||||||
|
|
||||||
|
private volatile byte[] content = null;
|
||||||
|
private volatile String contentType = null;
|
||||||
|
private volatile boolean useCaches = false;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile InputStream inputStream = null;
|
||||||
|
private volatile ByteArrayOutputStream outputStream = null;
|
||||||
|
|
||||||
|
private volatile String trueUrl = null;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile boolean connected = false;
|
||||||
|
private volatile int connectionDelay = 0;
|
||||||
|
|
||||||
|
private volatile boolean failed = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public HttpURLConnectionMock() {
|
||||||
|
super(MOCK_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpURLConnectionMock(URL u) {
|
||||||
|
super(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String getTrueUrl() {
|
||||||
|
return trueUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrueUrl(String url) {
|
||||||
|
assertNull(this.trueUrl);
|
||||||
|
this.trueUrl = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean hasFailed() {
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setConnectionDelay(int delay) {
|
||||||
|
this.connectionDelay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() {
|
||||||
|
if (!connected) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(connectionDelay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean usingProxy() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getInstanceFollowRedirects() {
|
||||||
|
return this.instanceFollowRedirects;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInstanceFollowRedirects(boolean followRedirects) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.instanceFollowRedirects = followRedirects;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestMethod() {
|
||||||
|
return this.requestMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRequestMethod(String method) throws ProtocolException {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.requestMethod = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getResponseCode() throws IOException {
|
||||||
|
connect();
|
||||||
|
return this.responseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResponseCode(int code) {
|
||||||
|
this.responseCode = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addRequestProperty(String key, String value) {
|
||||||
|
assertFalse(connected);
|
||||||
|
assertFalse(this.requestProperties.containsKey(key.toLowerCase()));
|
||||||
|
this.requestProperties.put(key.toLowerCase(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRequestProperty(String key, String value) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.requestProperties.put(key.toLowerCase(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestProperty(String key) {
|
||||||
|
return this.requestProperties.get(key.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConnectTimeout() {
|
||||||
|
return this.connectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setConnectTimeout(int timeout) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.connectTimeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentEncoding() {
|
||||||
|
connect();
|
||||||
|
return this.contentEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentEncoding(String encoding) {
|
||||||
|
this.contentEncoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getContentLength() {
|
||||||
|
connect();
|
||||||
|
if (content == null)
|
||||||
|
return 0;
|
||||||
|
return content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(byte[] content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
try {
|
||||||
|
this.content = content.getBytes("UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
fail("UTF-8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
connect();
|
||||||
|
return this.contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String type) {
|
||||||
|
this.contentType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDoInput() {
|
||||||
|
return this.doInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDoInput(boolean doinput) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.doInput = doinput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDoOutput() {
|
||||||
|
return this.doOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDoOutput(boolean dooutput) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.doOutput = dooutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
assertTrue(doInput);
|
||||||
|
assertNull(inputStream);
|
||||||
|
assertNotNull(content);
|
||||||
|
|
||||||
|
connect();
|
||||||
|
inputStream = new ByteArrayInputStream(content);
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream getOutputStream() throws IOException {
|
||||||
|
assertTrue(doOutput);
|
||||||
|
assertNull(outputStream);
|
||||||
|
outputStream = new ByteArrayOutputStream();
|
||||||
|
return outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getOutputStreamData() {
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutputStreamString() {
|
||||||
|
try {
|
||||||
|
return outputStream.toString("UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
fail("UTF-8");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseCaches(boolean usecaches) {
|
||||||
|
assertFalse(connected);
|
||||||
|
this.useCaches = usecaches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getUseCaches() {
|
||||||
|
return this.useCaches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void assertNull(Object o) {
|
||||||
|
try {
|
||||||
|
org.junit.Assert.assertNull(o);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotNull(Object o) {
|
||||||
|
try {
|
||||||
|
org.junit.Assert.assertNotNull(o);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertTrue(boolean o) {
|
||||||
|
try {
|
||||||
|
org.junit.Assert.assertTrue(o);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertFalse(boolean o) {
|
||||||
|
try {
|
||||||
|
org.junit.Assert.assertFalse(o);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fail(String msg) {
|
||||||
|
failed = true;
|
||||||
|
org.junit.Assert.fail(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getErrorStream() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeaderField(int n) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getHeaderFieldDate(String name, long Default) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeaderFieldKey(int n) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Permission getPermission() throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResponseMessage() throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChunkedStreamingMode(int chunklen) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFixedLengthStreamingMode(int contentLength) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getAllowUserInteraction() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getContent() throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public Object getContent(Class[] classes) throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDate() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDefaultUseCaches() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getExpiration() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeaderField(String name) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeaderFieldInt(String name, int Default) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getHeaderFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getIfModifiedSince() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastModified() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReadTimeout() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getRequestProperties() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getURL() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAllowUserInteraction(boolean allowuserinteraction) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultUseCaches(boolean defaultusecaches) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIfModifiedSince(long ifmodifiedsince) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadTimeout(int timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
229
test/net/sf/openrocket/communication/UpdateInfoTest.java
Normal file
229
test/net/sf/openrocket/communication/UpdateInfoTest.java
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
package net.sf.openrocket.communication;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.sf.openrocket.util.ComparablePair;
|
||||||
|
import net.sf.openrocket.util.Prefs;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UpdateInfoTest {
|
||||||
|
|
||||||
|
/** The connection delay */
|
||||||
|
private static final int DELAY = 100;
|
||||||
|
|
||||||
|
/** How much long does the test allow it to take */
|
||||||
|
private static final int ALLOWANCE = 2000;
|
||||||
|
|
||||||
|
|
||||||
|
private HttpURLConnectionMock setup() {
|
||||||
|
HttpURLConnectionMock connection = new HttpURLConnectionMock();
|
||||||
|
Communicator.setConnectionSource(new ConnectionSourceStub(connection));
|
||||||
|
|
||||||
|
connection.setConnectionDelay(DELAY);
|
||||||
|
connection.setUseCaches(true);
|
||||||
|
connection.setContentType("text/plain");
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(HttpURLConnectionMock connection) {
|
||||||
|
assertEquals(Communicator.UPDATE_INFO_URL + "?version=" + Prefs.getVersion(),
|
||||||
|
connection.getTrueUrl());
|
||||||
|
assertTrue(connection.getConnectTimeout() > 0);
|
||||||
|
assertEquals(Prefs.getVersion(), connection.getRequestProperty("X-OpenRocket-Version"));
|
||||||
|
assertNotNull(connection.getRequestProperty("X-OpenRocket-Country"));
|
||||||
|
assertNotNull(connection.getRequestProperty("X-OpenRocket-ID"));
|
||||||
|
assertNotNull(connection.getRequestProperty("X-OpenRocket-OS"));
|
||||||
|
assertNotNull(connection.getRequestProperty("X-OpenRocket-Java"));
|
||||||
|
assertTrue(connection.getInstanceFollowRedirects());
|
||||||
|
assertEquals("GET", connection.getRequestMethod());
|
||||||
|
assertFalse(connection.getUseCaches());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAvailable() throws IOException {
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE);
|
||||||
|
|
||||||
|
String content =
|
||||||
|
"Version: 6.6.6pre A \n" +
|
||||||
|
"Extra: information\n" +
|
||||||
|
"100:hundred\n" +
|
||||||
|
"50: m\u00e4 \n\n" +
|
||||||
|
"1: one\n" +
|
||||||
|
"-2: none";
|
||||||
|
connection.setContent(content);
|
||||||
|
|
||||||
|
UpdateInfoRetriever retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
|
||||||
|
// Info is null while processing
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
|
||||||
|
UpdateInfo info = retriever.getUpdateInfo();
|
||||||
|
assertNotNull(info);
|
||||||
|
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
assertEquals("6.6.6pre A", info.getLatestVersion());
|
||||||
|
|
||||||
|
List<ComparablePair<Integer, String>> updates = info.getUpdates();
|
||||||
|
assertEquals(3, updates.size());
|
||||||
|
Collections.sort(updates);
|
||||||
|
assertEquals(1, (int)updates.get(0).getU());
|
||||||
|
assertEquals("one", updates.get(0).getV());
|
||||||
|
assertEquals(50, (int)updates.get(1).getU());
|
||||||
|
assertEquals("m\u00e4", updates.get(1).getV());
|
||||||
|
assertEquals(100, (int)updates.get(2).getU());
|
||||||
|
assertEquals("hundred", updates.get(2).getV());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateNotAvailable() throws IOException {
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_NO_UPDATE_CODE);
|
||||||
|
|
||||||
|
String content =
|
||||||
|
"Version: 6.6.6pre A \n" +
|
||||||
|
"Extra: information\n" +
|
||||||
|
"100:hundred\n" +
|
||||||
|
"50: m\u00e4 \n\n" +
|
||||||
|
"1: one\n" +
|
||||||
|
"-2: none";
|
||||||
|
connection.setContent(content);
|
||||||
|
|
||||||
|
UpdateInfoRetriever retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
|
||||||
|
// Info is null while processing
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
|
||||||
|
UpdateInfo info = retriever.getUpdateInfo();
|
||||||
|
assertNotNull(info);
|
||||||
|
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
assertEquals(Prefs.getVersion(), info.getLatestVersion());
|
||||||
|
assertEquals(0, info.getUpdates().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidResponses() {
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(404);
|
||||||
|
connection.setContent("Version: 1.2.3");
|
||||||
|
|
||||||
|
UpdateInfoRetriever retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
|
||||||
|
connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE);
|
||||||
|
connection.setContentType("text/xml");
|
||||||
|
|
||||||
|
retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE);
|
||||||
|
String content =
|
||||||
|
"100:hundred\n" +
|
||||||
|
"50: m\u00e4 \n\n" +
|
||||||
|
"1: one\n";
|
||||||
|
connection.setContent(content);
|
||||||
|
|
||||||
|
retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
|
||||||
|
connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE);
|
||||||
|
connection.setContent(new byte[0]);
|
||||||
|
|
||||||
|
retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
check(connection);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRandomInputData() {
|
||||||
|
|
||||||
|
Random rnd = new Random();
|
||||||
|
for (int i=0; i<10; i++) {
|
||||||
|
int size = (int) ((1 + 0.3 * rnd.nextGaussian()) * Math.pow(i, 6));
|
||||||
|
byte[] buf = new byte[size];
|
||||||
|
rnd.nextBytes(buf);
|
||||||
|
|
||||||
|
HttpURLConnectionMock connection = setup();
|
||||||
|
connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE);
|
||||||
|
connection.setContent(buf);
|
||||||
|
|
||||||
|
UpdateInfoRetriever retriever = new UpdateInfoRetriever();
|
||||||
|
retriever.start();
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
waitfor(retriever);
|
||||||
|
assertFalse(connection.hasFailed());
|
||||||
|
assertNull(retriever.getUpdateInfo());
|
||||||
|
check(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void waitfor(UpdateInfoRetriever retriever) {
|
||||||
|
long t = System.currentTimeMillis();
|
||||||
|
|
||||||
|
while (retriever.isRunning()) {
|
||||||
|
if (System.currentTimeMillis() >= t+ALLOWANCE) {
|
||||||
|
fail("retriever took too long to respond");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Waiting took " + (System.currentTimeMillis()-t) + " ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,6 +13,9 @@ public class ComponentCompareTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComponentEquality() {
|
public void testComponentEquality() {
|
||||||
|
|
||||||
|
System.out.println("TEST CLASSPATH: " + System.getProperty("java.class.path"));
|
||||||
|
|
||||||
Rocket r1 = net.sf.openrocket.util.TestRockets.makeBigBlue();
|
Rocket r1 = net.sf.openrocket.util.TestRockets.makeBigBlue();
|
||||||
Rocket r2 = net.sf.openrocket.util.TestRockets.makeBigBlue();
|
Rocket r2 = net.sf.openrocket.util.TestRockets.makeBigBlue();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user