diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 44139c6f..edc480f6 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -1,16 +1,22 @@ package seng302.controllers; import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.paint.*; import javafx.scene.paint.Color; +import seng302.models.Boat; import seng302.models.parsers.StreamPacket; import seng302.models.parsers.StreamParser; @@ -33,6 +39,14 @@ public class Controller implements Initializable { private Button streamButton; @FXML private Button switchToRaceViewButton; + @FXML + private TableView teamList; + @FXML + private TableColumn boatNameCol; + @FXML + private TableColumn shortNameCol; + @FXML + private TableColumn countryCol; private void setContentPane(String jfxUrl){ try{ @@ -72,6 +86,7 @@ public class Controller implements Initializable { timeTillLive.setText("Race finished! Waiting for new race..."); switchToRaceViewButton.setDisable(true); } else if (StreamParser.getTimeSinceStart() > 0 && StreamParser.getTimeSinceStart() % 10 == 0) { + updateTeamList(); timeTillLive.setTextFill(Color.RED); switchToRaceViewButton.setDisable(false); Long timerMinute = StreamParser.getTimeSinceStart() / 60; @@ -79,6 +94,7 @@ public class Controller implements Initializable { String timerString = "-" + timerMinute + "." + timerSecond + " minutes"; timeTillLive.setText(timerString); } else if (StreamParser.getTimeSinceStart() % 10 == 0) { + updateTeamList(); timeTillLive.setTextFill(Color.BLACK); switchToRaceViewButton.setDisable(false); Long timerMinute = -1 * StreamParser.getTimeSinceStart() / 60; @@ -98,4 +114,21 @@ public class Controller implements Initializable { public void switchToRaceView() { setContentPane("/views/RaceView.fxml"); } + + private void updateTeamList() { + ObservableList data = FXCollections.observableArrayList(); + teamList.setItems(data); + boatNameCol.setCellValueFactory( + new PropertyValueFactory("boatName") + ); + shortNameCol.setCellValueFactory( + new PropertyValueFactory("shortName") + ); + countryCol.setCellValueFactory( + new PropertyValueFactory("country") + ); + for (Boat boat : StreamParser.getBoats()) { + data.add(boat); + } + } } diff --git a/src/main/java/seng302/models/Boat.java b/src/main/java/seng302/models/Boat.java index 04ef14ab..dc3aa7b7 100644 --- a/src/main/java/seng302/models/Boat.java +++ b/src/main/java/seng302/models/Boat.java @@ -21,6 +21,10 @@ public class Boat { private int markLastPast; private String shortName; private int id; + // new attributes to boat + private int sourceID; + private String boatName; + private String country; public Boat(String teamName) { this.teamName = teamName; @@ -45,6 +49,21 @@ public class Boat { this.id = id; } + /** + * New instance created by BoatsParser. + * + * @param sourceID source ID of the boat + * @param boatName full name of the boat + * @param shortName short name of the boat + * @param country country of the boat + */ + public Boat(int sourceID, String boatName, String shortName, String country) { + this.sourceID = sourceID; + this.boatName = boatName; + this.shortName = shortName; + this.country = country; + } + /** * Returns the name of the team sailing the boat * @@ -141,4 +160,15 @@ public class Boat { return id; } + public int getSourceID() { + return sourceID; + } + + public String getBoatName() { + return boatName; + } + + public String getCountry() { + return country; + } } \ No newline at end of file diff --git a/src/main/java/seng302/models/parsers/BoatsParser.java b/src/main/java/seng302/models/parsers/BoatsParser.java new file mode 100644 index 00000000..8180bde8 --- /dev/null +++ b/src/main/java/seng302/models/parsers/BoatsParser.java @@ -0,0 +1,77 @@ +package seng302.models.parsers; + +import org.w3c.dom.*; +import org.xml.sax.InputSource; +import seng302.models.Boat; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.InputStream; +import java.io.StringBufferInputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * Created by ryan_ on 30/04/2017. + */ +public class BoatsParser extends FileParser { + private Document doc; + + public BoatsParser(String xmlString) { + this.doc = this.parseFile(xmlString); + } + + /** + * Create a boat instance from a given node if 'Type' is 'Yacht' + * + * @param node a boat node + * @return an instance of Boat + */ + private Boat parseBoat(Node node) { + try { + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + if (element.getAttribute("Type").equals("Yacht")) { + String sourceID = element.getAttribute("SourceID"); + String boatName = element.getAttribute("BoatName"); + String shortName = element.getAttribute("ShortName"); + String stoweName = element.getAttribute("StoweName"); + String country = element.getAttribute("Country"); + Boat boat = new Boat(Integer.parseInt(sourceID), boatName, shortName, country); + return boat; + } + } else { + throw new NoSuchElementException("Cannot generate a boat by given node"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Returns a list of boats from the xml. + * + * @return a list of boats + */ + public List getBoats() { + ArrayList boats = new ArrayList<>(); + + try { + NodeList nodes = this.doc.getElementsByTagName("Boat"); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + Boat boat = parseBoat(node); + if (!(boat == null)) { + boats.add(boat); + } + } + return boats; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/seng302/models/parsers/FileParser.java b/src/main/java/seng302/models/parsers/FileParser.java index b3d66b05..be162b9e 100644 --- a/src/main/java/seng302/models/parsers/FileParser.java +++ b/src/main/java/seng302/models/parsers/FileParser.java @@ -1,12 +1,14 @@ package seng302.models.parsers; import org.w3c.dom.Document; +import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; /** * Created by Haoming Yin (hyi25) on 16/3/2017 @@ -15,6 +17,8 @@ public abstract class FileParser { private String filePath; + public FileParser() {} + public FileParser(String path) { this.filePath = path; } @@ -32,6 +36,19 @@ public abstract class FileParser { e.printStackTrace(); return null; } + } + protected Document parseFile(String xmlString) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new InputSource(new StringReader(xmlString))); + // optional, in order to recover info from broken line. + doc.getDocumentElement().normalize(); + return doc; + } catch (Exception e) { + e.printStackTrace(); + } + return null; } } diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index acb8e0f8..521d222d 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -5,6 +5,7 @@ import javafx.geometry.Point3D; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import seng302.models.Boat; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -35,6 +36,7 @@ public class StreamParser extends Thread{ private static boolean raceFinished = false; private static boolean streamStatus = false; private static long timeSinceStart = -1; + private static List boats = new ArrayList<>(); public StreamParser(String threadName){ this.threadName = threadName; @@ -221,19 +223,25 @@ public class StreamParser extends Thread{ //Converts XML message to string to be parsed int currentChar; while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) { - xmlMessage += (char)currentChar; + xmlMessage += (char)currentChar; + } + + // Parse boat xml from server + if (xmlMessageSubType == 7) { + BoatsParser boatsParser = new BoatsParser(xmlMessage); + boats = boatsParser.getBoats(); } //Create XML document Object - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = null; - try { - db = dbf.newDocumentBuilder(); - Document doc = db.parse(new InputSource(new StringReader(xmlMessage))); - // TODO: 25/04/17 ajm412: Check that the object matches expected structure and return Document object. - } catch (ParserConfigurationException | IOException | SAXException e) { - e.printStackTrace(); - } +// DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); +// DocumentBuilder db = null; +// try { +// db = dbf.newDocumentBuilder(); +// Document doc = db.parse(new InputSource(new StringReader(xmlMessage))); +// // TODO: 25/04/17 ajm412: Check that the object matches expected structure and return Document object. +// } catch (ParserConfigurationException | IOException | SAXException e) { +// e.printStackTrace(); +// } } @@ -444,5 +452,14 @@ public class StreamParser extends Thread{ public static boolean isRaceFinished() { return raceFinished; } + + /** + * return list of boats from the server + * + * @return list of boats + */ + public static List getBoats() { + return boats; + } } diff --git a/src/main/resources/views/MainView.fxml b/src/main/resources/views/MainView.fxml index 15559900..ebea61a2 100644 --- a/src/main/resources/views/MainView.fxml +++ b/src/main/resources/views/MainView.fxml @@ -1,5 +1,6 @@ + @@ -14,10 +15,12 @@ - - - - + + + + + +