Added connection screen to allow users to select available hosts from a preconfigured list.

- Added ConnectionController for initial client setup
- Added RaceConnection class for socket data and checking
- Configures StartController with a socket drawn from a host table

#story[782]
main
Connor Taylor-Brown 9 years ago
parent ad58407021
commit ac4fbda848

@ -22,9 +22,9 @@ public class App extends Application {
} }
public void start(Stage stage) throws Exception { public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/scenes/connect.fxml")); FXMLLoader loader = new FXMLLoader(getClass().getResource("/scenes/main.fxml"));
Parent root = loader.load(); Parent root = loader.load();
Scene scene = new Scene(root, 600, 400); Scene scene = new Scene(root, 1200, 800);
stage.setScene(scene); stage.setScene(scene);
stage.show(); stage.show();
} }

@ -1,10 +1,19 @@
package seng302.Controllers; package seng302.Controllers;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.AnchorPane;
import seng302.RaceConnection;
import javax.swing.text.TableView; import java.io.IOException;
import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
/** /**
@ -12,10 +21,53 @@ import java.util.ResourceBundle;
*/ */
public class ConnectionController extends Controller { public class ConnectionController extends Controller {
@FXML @FXML
TableView connectionTable; private AnchorPane connectionWrapper;
@FXML
private TableView connectionTable;
@FXML
private TableColumn<RaceConnection, String> hostnameColumn;
@FXML
private TableColumn<RaceConnection, String> statusColumn;
@FXML
private Button connectButton;
private List<RaceConnection> connections;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
// TODO - replace with config file
connections = new ArrayList<>();
connections.add(new RaceConnection("livedata.americascup.com", 4941));
connections.add(new RaceConnection("localhost", 4942));
connectionTable.setItems(FXCollections.observableArrayList(connections));
hostnameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
connectionTable.getSelectionModel().selectedItemProperty().addListener((obs, prev, curr) -> {
if (curr != null && ((RaceConnection)curr).check()) connectButton.setDisable(false);
else connectButton.setDisable(true);
});
}
/**
* Sets current status of all connections.
*/
public void checkConnections() {
for(RaceConnection connection: connections) {
connection.check();
}
}
/**
* Connects to host currently selected in table. Button enabled only if host is ready.
*/
public void connectSocket() {
try{
RaceConnection connection = (RaceConnection)connectionTable.getSelectionModel().getSelectedItem();
Socket socket = new Socket(connection.getHostname(), connection.getPort());
connectionWrapper.setVisible(false);
parent.enterLobby(socket);
} catch (IOException e) { /* Never reached */ }
} }
} }

@ -5,6 +5,7 @@ import javafx.scene.layout.AnchorPane;
import seng302.RaceDataSource; import seng302.RaceDataSource;
import seng302.VisualiserInput; import seng302.VisualiserInput;
import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -23,6 +24,9 @@ public class MainController extends Controller {
raceController.startRace(visualiserInput); raceController.startRace(visualiserInput);
} }
public void enterLobby(Socket socket) {
startController.enterLobby(socket);
}
/** /**
* Main Controller for the applications will house the menu and the displayed pane. * Main Controller for the applications will house the menu and the displayed pane.

@ -12,24 +12,18 @@ import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import org.xml.sax.SAXException;
import seng302.Mock.*; import seng302.Mock.*;
import seng302.Model.Boat; import seng302.Model.Boat;
import seng302.Model.RaceClock; import seng302.Model.RaceClock;
import seng302.VisualiserInput; import seng302.VisualiserInput;
import seng302.RaceDataSource;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.stream.Stream;
/** /**
* Created by esa46 on 6/04/17. * Created by esa46 on 6/04/17.
@ -88,29 +82,8 @@ public class StartController extends Controller implements Observer {
@Override @Override
public void initialize(URL location, ResourceBundle resources){ public void initialize(URL location, ResourceBundle resources){
raceData = null; raceData = new StreamedCourse();
try { raceData.addObserver(this);
raceData = new StreamedCourse();
raceData.addObserver(this);
// visualiserInput = new VisualiserInput(new Socket("livedata.americascup.com", 4941), raceData);
// visualiserInput = new VisualiserInput(new Socket("132.181.15.116", 8085), raceData);
visualiserInput = new VisualiserInput(new Socket(InetAddress.getLocalHost(), 4942), raceData);
new Thread(visualiserInput).start();
// StreamedCourse streamedCourse = new StreamedCourse(new BoatXMLReader("mockXML/boatXML/boatTest.xml"));
// streamedCourse.setStreamedCourseXMLReader(new StreamedCourseXMLReader("mockXML/raceXML/raceTest.xml"));
// streamedCourse.setRegattaXMLReader(new RegattaXMLReader("mockXML/regattaXML/regattaTest.xml"));
// raceData = streamedCourse;
// }catch (ParseException e) {
// e.printStackTrace();
// } catch (ParserConfigurationException e) {
// e.printStackTrace();
// } catch (SAXException e) {
// e.printStackTrace();
// } catch (StreamedCourseXMLException e) {
// e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} }
public AnchorPane startWrapper(){ public AnchorPane startWrapper(){
@ -204,4 +177,18 @@ public class StartController extends Controller implements Observer {
} }
} }
} }
/**
* Show starting information for a race given a socket.
* @param socket network source of information
*/
public void enterLobby(Socket socket) {
startWrapper.setVisible(true);
try {
visualiserInput = new VisualiserInput(socket, raceData);
new Thread(visualiserInput).start();
} catch (IOException e) {
e.printStackTrace();
}
}
} }

@ -1,14 +1,53 @@
package seng302; package seng302;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.io.IOException;
import java.net.Socket;
/** /**
* Created by cbt24 on 3/05/17. * Created by cbt24 on 3/05/17.
*/ */
public class RaceConnection { public class RaceConnection {
private String hostname; private StringProperty hostname;
private int port; private int port;
private StringProperty status;
public RaceConnection(String hostname, int port) { public RaceConnection(String hostname, int port) {
this.hostname = hostname; this.hostname = new SimpleStringProperty(hostname);
this.port = port; this.port = port;
this.status = new SimpleStringProperty("");
check();
}
/**
* Tries to create a socket to hostname and port, indicates status after test.
*/
@SuppressWarnings("unused")
public boolean check() {
try(Socket s = new Socket(hostname.get(), port)) {
status.set("Ready");
return true;
} catch (IOException e) {}
status.set("Offline");
return false;
}
public String getHostname() {
return hostname.get();
}
public StringProperty hostnameProperty() {
return hostname;
}
public int getPort() {
return port;
}
public StringProperty statusProperty() {
return status;
} }
} }

@ -1,33 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.Button?>
<?import java.lang.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="seng302.Controllers.ConnectionController"> <AnchorPane fx:id="connectionWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.ConnectionController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="192.0" minWidth="10.0" prefWidth="50.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="444.0" minWidth="10.0" prefWidth="444.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="144.0" minWidth="10.0" prefWidth="56.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="129.0" minHeight="10.0" prefHeight="61.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="283.0" minHeight="10.0" prefHeight="239.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="114.0" minHeight="10.0" prefHeight="89.0" vgrow="SOMETIMES" />
</rowConstraints>
<children> <children>
<TableView prefHeight="500.0" prefWidth="900.0" GridPane.columnIndex="1" GridPane.rowIndex="1"> <GridPane fx:id="connection" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns> <columnConstraints>
<TableColumn prefWidth="217.0" text="Address" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="600.0" minWidth="10.0" prefWidth="600.0" />
<TableColumn prefWidth="226.0" text="Status" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="600.0" minWidth="10.0" prefWidth="600.0" />
</columns> </columnConstraints>
</TableView> <rowConstraints>
<Label text="RaceVision" GridPane.columnIndex="1" GridPane.halignment="CENTER"> <RowConstraints maxHeight="182.0" minHeight="10.0" prefHeight="182.0" vgrow="SOMETIMES" />
<font> <RowConstraints maxHeight="434.0" minHeight="10.0" prefHeight="434.0" vgrow="SOMETIMES" />
<Font size="24.0" /> <RowConstraints maxHeight="174.0" minHeight="10.0" prefHeight="174.0" vgrow="SOMETIMES" />
</font> </rowConstraints>
</Label> <children>
<Button disable="true" mnemonicParsing="false" text="Connect" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" /> <TableView fx:id="connectionTable" prefHeight="200.0" prefWidth="1080.0" GridPane.columnSpan="2" GridPane.rowIndex="1">
<columns>
<TableColumn fx:id="hostnameColumn" prefWidth="453.99998474121094" text="Host" />
<TableColumn fx:id="statusColumn" prefWidth="205.0" text="Status" />
</columns>
<GridPane.margin>
<Insets left="50.0" right="50.0" />
</GridPane.margin>
</TableView>
<Button mnemonicParsing="false" onAction="#checkConnections" text="Refresh" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
<GridPane.margin>
<Insets right="20.0" />
</GridPane.margin>
</Button>
<Button fx:id="connectButton" mnemonicParsing="false" onAction="#connectSocket" text="Connect" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="20.0" />
</GridPane.margin>
</Button>
<Label text="Welcome to RaceVision" GridPane.columnSpan="2" GridPane.halignment="CENTER">
<font>
<Font size="36.0" />
</font>
</Label>
</children>
</GridPane>
</children> </children>
</GridPane> </AnchorPane>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="main" xmlns="http://javafx.com/javafx/8"
fx:controller="seng302.Controllers.MainController"> <AnchorPane fx:id="main" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.MainController">
<children> <children>
<fx:include source="race.fxml" fx:id="race"/> <fx:include fx:id="race" source="race.fxml" />
<fx:include source="start.fxml" fx:id="start"/> <fx:include fx:id="start" source="start.fxml" />
<fx:include fx:id="connection" source="connect.fxml" />
</children> </children>
</AnchorPane> </AnchorPane>

@ -1,65 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.Button?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?> <?import javafx.scene.text.Text?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="startWrapper" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" xmlns="http://javafx.com/javafx/8" <AnchorPane fx:id="startWrapper" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" visible="false" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.StartController">
fx:controller="seng302.Controllers.StartController">
<children> <children>
<GridPane fx:id="start" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" <GridPane fx:id="start" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="372.0" minWidth="10.0" prefWidth="200.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="372.0" minWidth="10.0" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="394.0" minWidth="10.0" prefWidth="250.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="394.0" minWidth="10.0" prefWidth="250.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="416.0" minWidth="10.0" prefWidth="200.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="416.0" minWidth="10.0" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="241.0" minHeight="10.0" prefHeight="116.5" vgrow="SOMETIMES"/> <RowConstraints maxHeight="241.0" minHeight="10.0" prefHeight="116.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="383.0" minHeight="10.0" prefHeight="257.5" vgrow="SOMETIMES"/> <RowConstraints maxHeight="383.0" minHeight="10.0" prefHeight="257.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="50.5" vgrow="SOMETIMES"/> <RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="50.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES"/> <RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="53.5" vgrow="SOMETIMES"/> <RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="53.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="82.0" vgrow="SOMETIMES"/> <RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="82.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Welcome to RaceVision" GridPane.columnSpan="5" <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Welcome to RaceVision" GridPane.columnSpan="5" GridPane.halignment="CENTER">
GridPane.halignment="CENTER">
<font> <font>
<Font size="36.0"/> <Font size="36.0" />
</font> </font>
</Text> </Text>
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace1Min" <Button fx:id="oneMinButton" maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace1Min" prefWidth="100.0" text="1 Minute" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
prefWidth="100.0" fx:id="oneMinButton" text="1 Minute" GridPane.columnIndex="1"
GridPane.halignment="RIGHT" GridPane.rowIndex="4">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets />
</GridPane.margin> </GridPane.margin>
</Button> </Button>
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRaceNoScaling" <Button fx:id="fifteenMinButton" maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRaceNoScaling" prefWidth="100.0" text="15 Minutes" GridPane.columnIndex="3" GridPane.halignment="LEFT" GridPane.rowIndex="4" />
prefWidth="100.0" fx:id="fifteenMinButton" text="15 Minutes" GridPane.columnIndex="3" <Button fx:id="fiveMinButton" maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace5Min" prefWidth="100.0" text="5 Minutes" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
GridPane.halignment="LEFT" GridPane.rowIndex="4"/> <Label text="Select Race Duration:" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace5Min" <TableView fx:id="boatNameTable" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1">
prefWidth="100.0" fx:id="fiveMinButton" text="5 Minutes" GridPane.columnIndex="2"
GridPane.halignment="CENTER" GridPane.rowIndex="4"/>
<Label text="Select Race Duration:" GridPane.columnIndex="2" GridPane.halignment="CENTER"
GridPane.rowIndex="3"/>
<TableView fx:id="boatNameTable" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1"
GridPane.columnSpan="3" GridPane.rowIndex="1">
<columns> <columns>
<TableColumn fx:id="boatNameColumn" prefWidth="360.0" style="-fx-font-size: 16;" <TableColumn fx:id="boatNameColumn" prefWidth="360.0" style="-fx-font-size: 16;" text="Team Name" />
text="Team Name"/> <TableColumn fx:id="boatCodeColumn" prefWidth="133.0" style="-fx-font-size: 16;" text="Code" />
<TableColumn fx:id="boatCodeColumn" prefWidth="133.0" style="-fx-font-size: 16;" text="Code"/>
</columns> </columns>
</TableView> </TableView>
<Label fx:id="timeZoneTime" contentDisplay="CENTER" text="timeZoneTime" GridPane.columnIndex="2" <Label fx:id="timeZoneTime" contentDisplay="CENTER" text="timeZoneTime" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER"/> <Label fx:id="timer" text=" " GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="5" />
<Label fx:id="timer" text=" " GridPane.columnIndex="2" GridPane.halignment="CENTER"
GridPane.rowIndex="5"/>
</children> </children>
</GridPane> </GridPane>
</children> </children>

@ -0,0 +1,30 @@
package seng302;
import org.junit.Before;
import org.junit.Test;
import static org.testng.Assert.*;
/**
* Created by connortaylorbrown on 3/05/17.
*/
public class RaceConnectionTest {
private RaceConnection onlineConnection;
private RaceConnection offlineConnection;
@Before
public void setUp() {
onlineConnection = new RaceConnection("livedata.americascup.com", 4941);
offlineConnection = new RaceConnection("localhost", 4942);
}
@Test
public void onlineConnectionStatusReady() {
assertTrue(onlineConnection.check());
}
@Test
public void offlineConnectionStatusOffline() {
assertFalse(offlineConnection.check());
}
}
Loading…
Cancel
Save