first commit
This commit is contained in:
178
scripts/java/FGClient/src/FGFSDemo.java
Normal file
178
scripts/java/FGClient/src/FGFSDemo.java
Normal file
@@ -0,0 +1,178 @@
|
||||
// FGFSDemo.java - Simple demo application.
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import org.flightgear.fgfsclient.FGFSConnection;
|
||||
import org.flightgear.fgfsclient.PropertyPage;
|
||||
|
||||
|
||||
/**
|
||||
* Simple GUI demo.
|
||||
*
|
||||
* <p>This demo connects to a running FlightGear process and displays
|
||||
* the current altitude, longitude, and latitude in a GUI window, with
|
||||
* updates every second.</p>
|
||||
*
|
||||
* <p>Usage:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* fgfs --telnet=9000
|
||||
* java FGFSDemo localhost 9000
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public class FGFSDemo
|
||||
extends JFrame
|
||||
{
|
||||
|
||||
public FGFSDemo (String host, int port)
|
||||
throws IOException
|
||||
{
|
||||
super("FlightGear Client Console");
|
||||
|
||||
fgfs = new FGFSConnection(host, port);
|
||||
tabs = new JTabbedPane();
|
||||
pages = new HashMap();
|
||||
|
||||
PropertyPage page = new PropertyPage(fgfs, "Simulation");
|
||||
page.addField("/sim/aircraft", "Aircraft:");
|
||||
page.addField("/sim/startup/airport-id", "Airport ID:");
|
||||
page.addField("/sim/time/gmt", "Current time (GMT):");
|
||||
page.addField("/sim/startup/trim", "Trim on ground (true/false):");
|
||||
page.addField("/sim/sound/audible", "Sound enabled (true/false):");
|
||||
page.addField("/sim/startup/browser-app", "Web browser:");
|
||||
addPage(page);
|
||||
|
||||
page = new PropertyPage(fgfs, "View");
|
||||
page.addField("/sim/view-mode", "View mode:");
|
||||
page.addField("/sim/current-view/field-of-view",
|
||||
"Field of view (deg):");
|
||||
page.addField("/sim/current-view/pitch-offset-deg",
|
||||
"View pitch offset (deg):");
|
||||
page.addField("/sim/current-view/heading-offset-deg",
|
||||
"View heading offset (deg):");
|
||||
addPage(page);
|
||||
|
||||
page = new PropertyPage(fgfs, "Location");
|
||||
page.addField("/position/altitude-ft", "Altitude (ft):");
|
||||
page.addField("/position/longitude-deg", "Longitude (deg):");
|
||||
page.addField("/position/latitude-deg", "Latitude (deg):");
|
||||
page.addField("/orientation/roll-deg", "Roll (deg):");
|
||||
page.addField("/orientation/pitch-deg", "Pitch (deg):");
|
||||
page.addField("/orientation/heading-deg", "Heading (deg):");
|
||||
addPage(page);
|
||||
|
||||
page = new PropertyPage(fgfs, "Weather");
|
||||
page.addField("/environment/wind-from-heading-deg",
|
||||
"Wind direction (deg FROM):");
|
||||
page.addField("/environment/params/base-wind-speed-kt",
|
||||
"Wind speed (kt):");
|
||||
page.addField("/environment/params/gust-wind-speed-kt",
|
||||
"Maximum gust (kt):");
|
||||
page.addField("/environment/wind-from-down-fps",
|
||||
"Updraft (fps):");
|
||||
page.addField("/environment/temperature-degc", "Temperature (degC):");
|
||||
page.addField("/environment/dewpoint-degc", "Dewpoint (degC):");
|
||||
page.addField("/environment/pressure-sea-level-inhg",
|
||||
"Altimeter setting (inHG):");
|
||||
addPage(page);
|
||||
|
||||
page = new PropertyPage(fgfs, "Clouds");
|
||||
page.addField("/environment/clouds/layer[0]/type",
|
||||
"Layer 0 type:");
|
||||
page.addField("/environment/clouds/layer[0]/elevation-ft",
|
||||
"Layer 0 height (ft):");
|
||||
page.addField("/environment/clouds/layer[0]/thickness-ft",
|
||||
"Layer 0 thickness (ft):");
|
||||
page.addField("/environment/clouds/layer[1]/type",
|
||||
"Layer 1 type:");
|
||||
page.addField("/environment/clouds/layer[1]/elevation-ft",
|
||||
"Layer 1 height (ft):");
|
||||
page.addField("/environment/clouds/layer[1]/thickness-ft",
|
||||
"Layer 1 thickness (ft):");
|
||||
page.addField("/environment/clouds/layer[2]/type",
|
||||
"Layer 2 type:");
|
||||
page.addField("/environment/clouds/layer[2]/elevation-ft",
|
||||
"Layer 2 height (ft):");
|
||||
page.addField("/environment/clouds/layer[2]/thickness-ft",
|
||||
"Layer 2 thickness (ft):");
|
||||
page.addField("/environment/clouds/layer[3]/type",
|
||||
"Layer 3 type:");
|
||||
page.addField("/environment/clouds/layer[3]/elevation-ft",
|
||||
"Layer 3 height (ft):");
|
||||
page.addField("/environment/clouds/layer[3]/thickness-ft",
|
||||
"Layer 3 thickness (ft):");
|
||||
page.addField("/environment/clouds/layer[4]/type",
|
||||
"Layer 4 type:");
|
||||
page.addField("/environment/clouds/layer[4]/elevation-ft",
|
||||
"Layer 4 height (ft):");
|
||||
page.addField("/environment/clouds/layer[4]/thickness-ft",
|
||||
"Layer 4 thickness (ft):");
|
||||
addPage(page);
|
||||
|
||||
page = new PropertyPage(fgfs, "Velocities");
|
||||
page.addField("/velocities/airspeed-kt", "Airspeed (kt):");
|
||||
page.addField("/velocities/speed-down-fps", "Descent speed (fps):");
|
||||
addPage(page);
|
||||
|
||||
getContentPane().add(tabs);
|
||||
|
||||
new Thread(new Updater()).start();
|
||||
}
|
||||
|
||||
private void addPage (PropertyPage page)
|
||||
{
|
||||
tabs.add(page.getName(), new JScrollPane(page));
|
||||
pages.put(page.getName(), page);
|
||||
}
|
||||
|
||||
private FGFSConnection fgfs;
|
||||
private JTabbedPane tabs;
|
||||
private HashMap pages;
|
||||
|
||||
public static void main (String args[])
|
||||
throws Exception
|
||||
{
|
||||
if (args.length != 2) {
|
||||
System.err.println("Usage: FGFSDemo <host> <port>");
|
||||
System.exit(2);
|
||||
}
|
||||
FGFSDemo gui = new FGFSDemo(args[0], Integer.parseInt(args[1]));
|
||||
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
gui.pack();
|
||||
gui.show();
|
||||
}
|
||||
|
||||
class Updater
|
||||
implements Runnable
|
||||
{
|
||||
|
||||
public void run ()
|
||||
{
|
||||
while (true) {
|
||||
int index = tabs.getSelectedIndex();
|
||||
if (index > -1) {
|
||||
String name = tabs.getTitleAt(index);
|
||||
PropertyPage page = (PropertyPage)pages.get(name);
|
||||
try {
|
||||
page.update();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end of FGFSDemo.java
|
||||
@@ -0,0 +1,317 @@
|
||||
// FGFSConnection.java - client library for the FlightGear flight simulator.
|
||||
// Started June 2002 by David Megginson, david@megginson.com
|
||||
// This library is in the Public Domain and comes with NO WARRANTY.
|
||||
|
||||
package org.flightgear.fgfsclient;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
|
||||
/**
|
||||
* A connection to a running instance of FlightGear.
|
||||
*
|
||||
* <p>This class currently uses the FlightGear telnet interface,
|
||||
* though it may be modified to use a different TCP/IP interface in
|
||||
* the future. Client applications can use this library to examine
|
||||
* and modify internal FlightGear properties.</p>
|
||||
*
|
||||
* <p>To start FlightGear with the telnet server activated, use a
|
||||
* command like this (to listen on port 9000):</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* fgfs --telnet=9000
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>Then create a connection to FlightGear from your Java client
|
||||
* application:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* FGFSConnection fgfs = new FGFSConnection("localhost", 9000);
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>Now you can use the connection to get and set FlightGear
|
||||
* properties:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* double altitude = fgfs.getDouble("/position/altitude-ft");
|
||||
* fgfs.setDouble("/orientation/heading", 270.0);
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>All methods that communicate directly with FlightGear are
|
||||
* synchronized, since they must work over a single telnet
|
||||
* connection.</p>
|
||||
*/
|
||||
public class FGFSConnection
|
||||
{
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* <p>Create a new connection to a running FlightGear program.
|
||||
* The program must have been started with the --telnet=<port>
|
||||
* command-line option.</p>
|
||||
*
|
||||
* @param host The host name or IP address to connect to.
|
||||
* @param port The port number where FlightGear is listening.
|
||||
* @exception IOException If it is not possible to connect to
|
||||
* a FlightGear process.
|
||||
*/
|
||||
public FGFSConnection (String host, int port)
|
||||
throws IOException
|
||||
{
|
||||
socket = new Socket(host, port);
|
||||
in =
|
||||
new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
out = new PrintWriter(socket.getOutputStream(), true);
|
||||
out.println("data\r");
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Primitive getter and setter.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Close the connection to FlightGear.
|
||||
*
|
||||
* <p>The client application should always invoke this method when
|
||||
* it has finished with a connection, to allow cleanup.</p>
|
||||
*
|
||||
* @exception IOException If there is an error closing the
|
||||
* connection.
|
||||
*/
|
||||
public synchronized void close ()
|
||||
throws IOException
|
||||
{
|
||||
out.println("quit\r");
|
||||
in.close();
|
||||
out.close();
|
||||
socket.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the raw string value for a property.
|
||||
*
|
||||
* <p>This is the primitive method for all property lookup;
|
||||
* everything comes in as a string, and is only later converted by
|
||||
* methods like {@link #getDouble(String)}. As a result, if you
|
||||
* need the value as a string anyway, it makes sense to use this
|
||||
* method directly rather than forcing extra conversions.</p>
|
||||
*
|
||||
* @param name The FlightGear property name to look up.
|
||||
* @return The property value as a string (non-existant properties
|
||||
* return the empty string).
|
||||
* @exception IOException If there is an error communicating with
|
||||
* FlightGear or if the connection is lost.
|
||||
* @see #getBoolean(String)
|
||||
* @see #getInt(String)
|
||||
* @see #getLong(String)
|
||||
* @see #getFloat(String)
|
||||
* @see #getDouble(String)
|
||||
*/
|
||||
public synchronized String get (String name)
|
||||
throws IOException
|
||||
{
|
||||
out.println("get " + name + '\r');
|
||||
return in.readLine();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the raw string value for a property.
|
||||
*
|
||||
* <p>This is the primitive method for all property modification;
|
||||
* everything goes out as a string, after it has been converted by
|
||||
* methods like {@link #setDouble(String,double)}. As a result, if
|
||||
* you have the value as a string already, it makes sense to use
|
||||
* this method directly rather than forcing extra conversions.</p>
|
||||
*
|
||||
* @param name The FlightGear property name to modify or create.
|
||||
* @param value The new value for the property, as a string.
|
||||
* @exception IOException If there is an error communicating with
|
||||
* FlightGear or if the connection is lost.
|
||||
* @see #setBoolean(String,boolean)
|
||||
* @see #setInt(String,int)
|
||||
* @see #setLong(String,long)
|
||||
* @see #setFloat(String,float)
|
||||
* @see #setDouble(String,double)
|
||||
*/
|
||||
public synchronized void set (String name, String value)
|
||||
throws IOException
|
||||
{
|
||||
out.println("set " + name + ' ' + value + '\r');
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Derived getters and setters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Get a property value as a boolean.
|
||||
*
|
||||
* @param name The property name to look up.
|
||||
* @return The property value as a boolean.
|
||||
* @see #get(String)
|
||||
*/
|
||||
public boolean getBoolean (String name)
|
||||
throws IOException
|
||||
{
|
||||
return get(name).equals("true");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a property value as an integer.
|
||||
*
|
||||
* @param name The property name to look up.
|
||||
* @return The property value as an int.
|
||||
* @see #get(String)
|
||||
*/
|
||||
public int getInt (String name)
|
||||
throws IOException
|
||||
{
|
||||
return Integer.parseInt(get(name));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a property value as a long.
|
||||
*
|
||||
* @param name The property name to look up.
|
||||
* @return The property value as a long.
|
||||
* @see #get(String)
|
||||
*/
|
||||
public long getLong (String name)
|
||||
throws IOException
|
||||
{
|
||||
return Long.parseLong(get(name));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a property value as a float.
|
||||
*
|
||||
* @param name The property name to look up.
|
||||
* @return The property value as a float.
|
||||
* @see #get(String)
|
||||
*/
|
||||
public float getFloat (String name)
|
||||
throws IOException
|
||||
{
|
||||
return Float.parseFloat(get(name));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a property value as a double.
|
||||
*
|
||||
* @param name The property name to look up.
|
||||
* @return The property value as a double.
|
||||
* @see #get(String)
|
||||
*/
|
||||
public double getDouble (String name)
|
||||
throws IOException
|
||||
{
|
||||
return Double.parseDouble(get(name));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a property value from a boolean.
|
||||
*
|
||||
* @param name The property name to create or modify.
|
||||
* @param value The new property value as a boolean.
|
||||
* @see #set(String,String)
|
||||
*/
|
||||
public void setBoolean (String name, boolean value)
|
||||
throws IOException
|
||||
{
|
||||
set(name, (value ? "true" : "false"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a property value from an int.
|
||||
*
|
||||
* @param name The property name to create or modify.
|
||||
* @param value The new property value as an int.
|
||||
* @see #set(String,String)
|
||||
*/
|
||||
public void setInt (String name, int value)
|
||||
throws IOException
|
||||
{
|
||||
set(name, Integer.toString(value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a property value from a long.
|
||||
*
|
||||
* @param name The property name to create or modify.
|
||||
* @param value The new property value as a long.
|
||||
* @see #set(String,String)
|
||||
*/
|
||||
public void setLong (String name, long value)
|
||||
throws IOException
|
||||
{
|
||||
set(name, Long.toString(value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a property value from a float.
|
||||
*
|
||||
* @param name The property name to create or modify.
|
||||
* @param value The new property value as a float.
|
||||
* @see #set(String,String)
|
||||
*/
|
||||
public void setFloat (String name, float value)
|
||||
throws IOException
|
||||
{
|
||||
set(name, Float.toString(value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a property value from a double.
|
||||
*
|
||||
* @param name The property name to create or modify.
|
||||
* @param value The new property value as a double.
|
||||
* @see #set(String,String)
|
||||
*/
|
||||
public void setDouble (String name, double value)
|
||||
throws IOException
|
||||
{
|
||||
set(name, Double.toString(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Internal state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Socket socket;
|
||||
private BufferedReader in;
|
||||
private PrintWriter out;
|
||||
|
||||
}
|
||||
|
||||
// end of FGFSConnection.java
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.flightgear.fgfsclient;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
public class PropertyField
|
||||
extends JPanel
|
||||
{
|
||||
|
||||
public PropertyField (FGFSConnection fgfs,
|
||||
String name,
|
||||
String caption)
|
||||
{
|
||||
this.fgfs = fgfs;
|
||||
propertyName = name;
|
||||
label = new JLabel(caption);
|
||||
value = new JTextField(10);
|
||||
value.addActionListener(new ActionListener () {
|
||||
public void actionPerformed (ActionEvent ev)
|
||||
{
|
||||
try {
|
||||
modify();
|
||||
grabFocus();
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Failed to update " + propertyName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add(label);
|
||||
add(value);
|
||||
|
||||
}
|
||||
|
||||
public void update ()
|
||||
throws IOException
|
||||
{
|
||||
if (!value.hasFocus())
|
||||
value.setText(fgfs.get(propertyName));
|
||||
}
|
||||
|
||||
public void modify ()
|
||||
throws IOException
|
||||
{
|
||||
fgfs.set(propertyName, value.getText());
|
||||
}
|
||||
|
||||
private FGFSConnection fgfs;
|
||||
private String propertyName;
|
||||
private JLabel label;
|
||||
private JTextField value;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.flightgear.fgfsclient;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class PropertyPage
|
||||
extends JPanel
|
||||
{
|
||||
|
||||
public PropertyPage (FGFSConnection fgfs, String name)
|
||||
{
|
||||
this.fgfs = fgfs;
|
||||
this.name = name;
|
||||
fields = new ArrayList();
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
}
|
||||
|
||||
public String getName ()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void addField (String name, String caption)
|
||||
{
|
||||
PropertyField field = new PropertyField(fgfs, name, caption);
|
||||
add(field);
|
||||
fields.add(field);
|
||||
}
|
||||
|
||||
public void update ()
|
||||
throws IOException
|
||||
{
|
||||
Iterator it = fields.iterator();
|
||||
while (it.hasNext()) {
|
||||
((PropertyField)it.next()).update();
|
||||
}
|
||||
}
|
||||
|
||||
private FGFSConnection fgfs;
|
||||
private String name;
|
||||
private ArrayList fields;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.flightgear.fgfsclient;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
|
||||
public final class Util
|
||||
{
|
||||
|
||||
public static void forceConnection (JFrame frame, final FGFSConnection fgfs)
|
||||
{
|
||||
while (!fgfs.isConnected()) {
|
||||
final JDialog dialog =
|
||||
new JDialog(frame, "Connect to FlightGear", true);
|
||||
dialog.getContentPane().setLayout(new GridLayout(3, 2));
|
||||
dialog.getContentPane().add(new JLabel("Host:"));
|
||||
|
||||
final JTextField hostField = new JTextField(20);
|
||||
hostField.setText(fgfs.getHost());
|
||||
dialog.getContentPane().add(hostField);
|
||||
|
||||
dialog.getContentPane().add(new JLabel("Port:"));
|
||||
|
||||
final JTextField portField = new JTextField(5);
|
||||
portField.setText(Integer.toString(fgfs.getPort()));
|
||||
dialog.getContentPane().add(portField);
|
||||
|
||||
JButton connectButton = new JButton("Connect");
|
||||
connectButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed (ActionEvent ev)
|
||||
{
|
||||
try {
|
||||
fgfs.open(hostField.getText(),
|
||||
Integer.parseInt(portField.getText()));
|
||||
} catch (IOException ex) {
|
||||
JOptionPane.showMessageDialog(dialog, ex.getMessage(),
|
||||
"Alert", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
dialog.hide();
|
||||
}
|
||||
});
|
||||
dialog.getContentPane().add(connectButton);
|
||||
dialog.getRootPane().setDefaultButton(connectButton);
|
||||
|
||||
JButton quitButton = new JButton("Quit");
|
||||
quitButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed (ActionEvent ev)
|
||||
{
|
||||
System.exit(0); // FIXME
|
||||
}
|
||||
});
|
||||
dialog.getContentPane().add(quitButton);
|
||||
|
||||
dialog.pack();
|
||||
dialog.show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user