Merge branch 'develop' into Story47CourseLimits

# Conflicts:
#	src/main/resources/views/RaceView.fxml
This commit is contained in:
Kusal Ekanayake
2017-05-15 10:33:22 +12:00
12 changed files with 597 additions and 81 deletions
@@ -1,31 +1,31 @@
package seng302.controllers;
import javafx.animation.*;
import javafx.animation.AnimationTimer;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import seng302.models.*;
import seng302.models.BoatGroup;
import seng302.models.Colors;
import seng302.models.RaceObject;
import seng302.models.Yacht;
import seng302.models.mark.*;
import seng302.models.parsers.StreamParser;
import seng302.models.parsers.StreamReceiver;
import seng302.models.parsers.packets.BoatPositionPacket;
import seng302.models.parsers.XMLParser;
import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark;
import seng302.models.parsers.XMLParser.RaceXMLObject.Limit;
import seng302.models.mark.Mark;
import seng302.models.parsers.packets.BoatPositionPacket;
import java.text.DecimalFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.PriorityBlockingQueue;
/**
@@ -18,12 +18,8 @@ import seng302.models.Yacht;
import seng302.models.parsers.StreamParser;
import seng302.models.parsers.XMLParser;
import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
@@ -50,12 +46,13 @@ public class Controller implements Initializable {
@FXML
private Label realTime;
private XMLParser xmlParser;
private boolean switchedToRaceView = false;
private void setContentPane(String jfxUrl){
try{
contentPane.getChildren().removeAll();
contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
}
catch(javafx.fxml.LoadException e){
@@ -68,9 +65,8 @@ public class Controller implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
//DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
//format.setTimeZone(TimeZone.getTimeZone("GMT-8"));
//realTime.setText(format.format(new Date()));
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
teamList.getStylesheets().add(getClass().getResource("/css/master.css").toString());
}
/**
@@ -78,7 +74,6 @@ public class Controller implements Initializable {
*/
public void startStream() {
if (StreamParser.isStreamStatus()) {
xmlParser = StreamParser.getXmlObject();
streamButton.setVisible(false);
realTime.setVisible(true);
timeTillLive.setVisible(true);
@@ -90,7 +85,9 @@ public class Controller implements Initializable {
public void run() {
Platform.runLater(() -> {
if (StreamParser.isRaceStarted()) {
switchToRaceView();
if (!switchedToRaceView) {
switchToRaceView();
}
timer.cancel();
}
if (StreamParser.isRaceFinished()) {
@@ -133,12 +130,15 @@ public class Controller implements Initializable {
}
public void switchToRaceView() {
switchedToRaceView = true;
setContentPane("/views/RaceView.fxml");
}
private void updateTeamList() {
ObservableList<Yacht> data = FXCollections.observableArrayList();
teamList.setItems(data);
boatNameCol.setCellValueFactory(
new PropertyValueFactory<>("boatName")
);
@@ -151,18 +151,8 @@ public class Controller implements Initializable {
posCol.setCellValueFactory(
new PropertyValueFactory<>("position")
);
// if (StreamParser.isRaceStarted()) {
data.addAll(StreamParser.getBoatsPos().values());
// } else {
// for (Yacht boat : StreamParser.getBoats().values()) {
// boat.setPosition("-");
// data.add(boat);
// }
// }
teamList.refresh();
// posCol.setSortType(TableColumn.SortType.ASCENDING);
// teamList.getSortOrder().add(posCol);
// posCol.setSortable(false);
data.addAll(StreamParser.getBoatsPos().values());
teamList.refresh();
}
}
@@ -1,26 +1,31 @@
package seng302.controllers;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Slider;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import javafx.util.StringConverter;
import seng302.controllers.annotations.Annotation;
import seng302.controllers.annotations.ImportantAnnotationController;
import seng302.controllers.annotations.ImportantAnnotationDelegate;
import seng302.controllers.annotations.ImportantAnnotationsState;
import seng302.models.*;
import seng302.models.parsers.ConfigParser;
import seng302.models.parsers.StreamParser;
import java.io.IOException;
@@ -29,7 +34,7 @@ import java.util.*;
/**
* Created by ptg19 on 29/03/17.
*/
public class RaceViewController extends Thread{
public class RaceViewController extends Thread implements ImportantAnnotationDelegate{
@FXML
private VBox positionVbox;
@FXML
@@ -43,6 +48,8 @@ public class RaceViewController extends Thread{
@FXML
private Slider annotationSlider;
@FXML
private Button selectAnnotationBtn;
@FXML
private CanvasController includedCanvasController;
private ArrayList<Yacht> startingBoats = new ArrayList<>();
@@ -52,21 +59,19 @@ public class RaceViewController extends Thread{
private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race;
private Stage stage;
private ImportantAnnotationsState importantAnnotations;
public void initialize() {
// Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState();
RaceController raceController = new RaceController();
raceController.initializeRace();
race = raceController.getRace();
for (Yacht boat : race.getBoats()) {
startingBoats.add(boat);
}
// try{
// initializeTimelines();
// }
// catch (Exception e){
// e.printStackTrace();
// }
includedCanvasController.setup(this);
includedCanvasController.initializeCanvas();
@@ -79,9 +84,48 @@ public class RaceViewController extends Thread{
// windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection);
includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> {
loadSelectAnnotationView();
});
}
/**
* The important annotations have been changed, update this view
* @param importantAnnotationsState The current state of the selected annotations
*/
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState){
this.importantAnnotations = importantAnnotationsState;
setAnnotations((int)annotationSlider.getValue()); // Refresh the displayed annotations
}
/**
* Loads the "select annotations" view in a new window
*/
private void loadSelectAnnotationView() {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Stage stage = new Stage();
// Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(this, stage);
fxmlLoader.setController(controller);
// Load FXML and set CSS
fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 469, 248);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
controller.loadState(importantAnnotations);
} catch (IOException e) {
e.printStackTrace();
}
}
private void initializeSettings() {
displayFps = true;
@@ -93,13 +137,13 @@ public class RaceViewController extends Thread{
}
});
//SLIFER STUFF BELOW
//SLIDER STUFF BELOW
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override
public String toString(Double n) {
if (n == 0) return "None";
if (n == 1) return "Low";
if (n == 2) return "Medium";
if (n == 2) return "Important";
if (n == 3) return "All";
return "All";
@@ -112,7 +156,7 @@ public class RaceViewController extends Thread{
return 0d;
case "Low":
return 1d;
case "Medium":
case "Important":
return 2d;
case "All":
return 3d;
@@ -303,6 +347,7 @@ public class RaceViewController extends Thread{
private void showOrder() {
positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// for (Boat boat : boatOrder) {
// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots"));
@@ -310,11 +355,17 @@ public class RaceViewController extends Thread{
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status
positionVbox.getChildren().add(new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)"));
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else {
positionVbox.getChildren().add(new Text(boat.getPosition() + ". " +
boat.getShortName() + " "));
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
@@ -376,9 +427,43 @@ public class RaceViewController extends Thread{
return startingBoats;
}
/**
* Display the important annotations for a specific BoatGroup
* @param bg The boat group to set the annotations for
*/
private void setBoatGroupImportantAnnotations(BoatGroup bg){
if (importantAnnotations.getAnnotationState(Annotation.NAME)){
bg.setTeamNameObjectVisible(true);
}
else{
bg.setTeamNameObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.SPEED)){
bg.setVelocityObjectVisible(true);
}
else{
bg.setVelocityObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.TRACK)){
bg.setLineGroupVisible(true);
}
else{
bg.setLineGroupVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.WAKE)){
bg.setWakeVisible(true);
}
else{
bg.setWakeVisible(false);
}
}
private void setAnnotations(Integer annotationLevel) {
switch (annotationLevel) {
// No Annotations
case 0:
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) {
@@ -390,6 +475,7 @@ public class RaceViewController extends Thread{
}
}
break;
// Low Annotations
case 1:
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) {
@@ -401,17 +487,16 @@ public class RaceViewController extends Thread{
}
}
break;
// Important Annotations
case 2:
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) {
BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(false);
bg.setLineGroupVisible(true);
bg.setWakeVisible(false);
setBoatGroupImportantAnnotations(bg);
}
}
break;
// All Annotations
case 3:
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
if(ro instanceof BoatGroup) {
@@ -0,0 +1,11 @@
package seng302.controllers.annotations;
/**
* Annotations the user can select as important
*/
public enum Annotation {
SPEED,
WAKE,
TRACK,
NAME
}
@@ -0,0 +1,114 @@
package seng302.controllers.annotations;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import seng302.controllers.RaceViewController;
import seng302.controllers.annotations.Annotation;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
public class ImportantAnnotationController implements Initializable {
/*
* JavaFX Outlets
*/
@FXML
private CheckBox boatWakeSelect;
@FXML
private CheckBox boatSpeedSelect;
@FXML
private CheckBox boatTrackSelect;
@FXML
private CheckBox boatNameSelect;
@FXML
private AnchorPane annotationSelectWindow;
@FXML
private Button closeButton;
private ImportantAnnotationDelegate delegate;
private ImportantAnnotationsState importantAnnotationsState;
private Stage stage;
public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage){
this.delegate = delegate;
importantAnnotationsState = new ImportantAnnotationsState();
this.stage = stage;
}
/**
* Sets whether or not an annotation is considered important, then
* sends an update to the delegate
* @param annotation The annotation
* @param isSet True if annotation is important
*/
private void setAnnotation(Annotation annotation, Boolean isSet){
importantAnnotationsState.setAnnotationState(annotation, isSet);
sendUpdate();
}
/**
* Sends an update to the delegate when the important
* annotations have changed
*/
private void sendUpdate(){
this.delegate.importantAnnotationsChanged(importantAnnotationsState);
}
/**
* Load the current state of the 'important annotations'
* @param currentState hashmap containing the states of each annotation
*/
public void loadState(ImportantAnnotationsState currentState){
this.importantAnnotationsState = currentState;
// Initialise checkboxes
for (Annotation annotation : importantAnnotationsState.getAnnotations()){
switch (annotation){
case WAKE:
boatWakeSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case SPEED:
boatSpeedSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case TRACK:
boatTrackSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case NAME:
boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
default:
break;
}
}
}
/**
* View did load
* @param location .
* @param resources .
*/
@Override
public void initialize(URL location, ResourceBundle resources) {
boatWakeSelect.setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected()));
boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected()));
boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected()));
boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected()));
closeButton.setOnAction(event -> stage.close());
}
}
@@ -0,0 +1,16 @@
package seng302.controllers.annotations;
/**
* An ImportantAnnotationDelegate handles updating the important annotations
* displayed to the user on behalf of the ImportantAnnotationController
*/
public interface ImportantAnnotationDelegate {
/**
* The important annotations have been changed, update the
* annotations displayed to the user
* @param importantAnnotationsState The current state of the selected annotations
*/
void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState);
}
@@ -0,0 +1,52 @@
package seng302.controllers.annotations;
import java.util.HashMap;
import java.util.Map;
public class ImportantAnnotationsState {
public static final Boolean DEFAULT_ANNOTATION_STATE = true;
private Map<Annotation, Boolean> currentState;
/**
* Stores the users preference for the annotations
* they consider to be important
*/
public ImportantAnnotationsState(){
this.currentState = new HashMap<>();
initialiseState();
}
/**
* Set each annotation to the default annotation state
*/
private void initialiseState(){
for (Annotation annotation : getAnnotations()){
currentState.put(annotation, DEFAULT_ANNOTATION_STATE);
}
}
/**
* Sets the state (visibility) of an annotation
* @param annotation The annotation to set
* @param visible Whether or not the annotation should be visible
*/
public void setAnnotationState(Annotation annotation, Boolean visible){
this.currentState.put(annotation, visible);
}
/**
* Returns the state (visibility) of a specific annotation
* @param annotation The annotation to check
* @return True if visible, else false
*/
public Boolean getAnnotationState(Annotation annotation){
return this.currentState.containsKey(annotation) && this.currentState.get(annotation);
}
/**
* @return Return an array containing all defined annotations
*/
public Annotation[] getAnnotations(){
return Annotation.class.getEnumConstants();
}
}