Large tidying of RaceViewController class. Fixing updating for combo boxes

#story[955]
This commit is contained in:
William Muir
2017-05-16 15:06:01 +12:00
parent 51f090324a
commit 2d5a7a8a49
5 changed files with 95 additions and 203 deletions
+2 -2
View File
@@ -62,8 +62,8 @@ public class App extends Application
} }
//Change the StreamReceiver in this else block to change the default data source. //Change the StreamReceiver in this else block to change the default data source.
else{ else{
sr = new StreamReceiver("localhost", 4949, "RaceStream"); // sr = new StreamReceiver("localhost", 4949, "RaceStream");
// sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
} }
@@ -25,7 +25,7 @@ public class RaceController {
String teamsConfigFile = "/config/teams.xml"; String teamsConfigFile = "/config/teams.xml";
try { try {
race = createRace(raceConfigFile, teamsConfigFile); race = createRace(raceConfigFile, teamsConfigFile); //These config files arent actually used
} catch (Exception e) { } catch (Exception e) {
System.out.println("There was an error creating the race."); System.out.println("There was an error creating the race.");
} }
@@ -1,12 +1,8 @@
package seng302.controllers; package seng302.controllers;
import javafx.animation.Animation;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableArray;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
@@ -62,15 +58,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private boolean displayFps; private boolean displayFps;
private Timeline timerTimeline; private Timeline timerTimeline;
private Map<Yacht, TimelineInfo> timelineInfos = new HashMap<>(); private Map<Yacht, TimelineInfo> timelineInfos = new HashMap<>();
private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race; private Race race;
private Stage stage; private Stage stage;
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
private Yacht selectedBoat;
public void initialize() { public void initialize() {
// Load a default important annotation state // Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState(); importantAnnotations = new ImportantAnnotationsState();
//Initialise race controller
RaceController raceController = new RaceController(); RaceController raceController = new RaceController();
raceController.initializeRace(); raceController.initializeRace();
race = raceController.getRace(); race = raceController.getRace();
@@ -79,15 +77,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
includedCanvasController.setup(this); includedCanvasController.setup(this);
includedCanvasController.initializeCanvas(); includedCanvasController.initializeCanvas();
initializeTimer(); initializeUpdateTimer();
initializeSettings(); initialiseFPSCheckBox();
initialiseWindDirection(); initialiseAnnotationSlider();
initialisePositionVBox();
initialiseBoatSelectionComboBox(); initialiseBoatSelectionComboBox();
//set wind direction!!!!!!! can't find another place to put my code --haoming
// double windDirection = new ConfigParser("/config/config.xml").getWindDirection();
// windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection);
includedCanvasController.timer.start(); includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> { selectAnnotationBtn.setOnAction(event -> {
@@ -132,17 +125,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
private void initializeSettings() {
private void initialiseFPSCheckBox() {
displayFps = true; displayFps = true;
toggleFps.selectedProperty().addListener(
toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() { (observable, oldValue, newValue) -> displayFps = !displayFps);
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
displayFps = !displayFps;
} }
});
//SLIDER STUFF BELOW private void initialiseAnnotationSlider() {
annotationSlider.setLabelFormatter(new StringConverter<Double>() { annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override @Override
public String toString(Double n) { public String toString(Double n) {
@@ -175,19 +165,24 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
annotationSlider.setValue(2); annotationSlider.setValue(2);
} }
private void initializeTimer(){
/**
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
* orderings etc.. which are dependent on the info from the stream parser constantly.
* Updates of each of these attributes are called ONCE EACH SECOND
*/
private void initializeUpdateTimer(){
timerTimeline = new Timeline(); timerTimeline = new Timeline();
timerTimeline.setCycleCount(Timeline.INDEFINITE); timerTimeline.setCycleCount(Timeline.INDEFINITE);
// Run timer update every second // Run timer update every second
timerTimeline.getKeyFrames().add( timerTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1), new KeyFrame(Duration.seconds(1),
event -> { event -> {
if (StreamParser.isRaceFinished()) { updateRaceTime();
timerLabel.setFill(Color.RED); updateWindDirection();
timerLabel.setText("Race Finished!"); updateOrder();
} else { updateBoatSelectionComboBox();
timerLabel.setText(currentTimer());
}
}) })
); );
@@ -195,133 +190,82 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
timerTimeline.playFromStart(); timerTimeline.playFromStart();
} }
private void initialiseWindDirection() {
Timeline windDirTimeline = new Timeline(); /**
windDirTimeline.setCycleCount(Timeline.INDEFINITE); * Updates the wind direction arrow and text as from info from the StreamParser
windDirTimeline.getKeyFrames().add( */
new KeyFrame(Duration.seconds(1), private void updateWindDirection() {
event -> {
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection())); windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection()));
windArrowText.setRotate(StreamParser.getWindDirection()); windArrowText.setRotate(StreamParser.getWindDirection());
})
);
windDirTimeline.playFromStart();
} }
private void initialisePositionVBox() {
Timeline posVBoxTimeline = new Timeline();
posVBoxTimeline.setCycleCount(Timeline.INDEFINITE);
posVBoxTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
event -> {
showOrder();
})
);
posVBoxTimeline.playFromStart();
/**
* Updates the clock for the race
*/
private void updateRaceTime() {
if (StreamParser.isRaceFinished()) {
timerLabel.setFill(Color.RED);
timerLabel.setText("Race Finished!");
} else {
timerLabel.setText(getTimeSinceStartOfRace());
}
} }
private void initialiseBoatSelectionComboBox() {
ObservableList<Yacht> observableBoats = FXCollections.observableArrayList(startingBoats); /**
* Grabs the boats currently in the race as from the StreamParser and sets them to be selectable
* in the boat selection combo box
*/
private void updateBoatSelectionComboBox() {
ObservableList<Yacht> observableBoats = FXCollections.observableArrayList(StreamParser.getBoatsPos().values());
boatSelectionComboBox.setItems(observableBoats); boatSelectionComboBox.setItems(observableBoats);
}
/**
* Updates the order of the boats as from the StreamParser and sets them in the boat order section
*/
private void updateOrder() {
positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else {
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
}
/**
* Initialised the combo box with any boats currently in the race and adds the required listener
* for the combobox to take action upon selection
*/
private void initialiseBoatSelectionComboBox() {
updateBoatSelectionComboBox();
boatSelectionComboBox.valueProperty().addListener((observable, oldValue, newValue) -> { boatSelectionComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
//This listener is fired whenever the combo box changes. This means when the values are updated
//We dont want to set the selected value if the values are updated but nothing clicked (null)
if (newValue != null && newValue != selectedBoat) {
Yacht thisYacht = (Yacht) newValue; Yacht thisYacht = (Yacht) newValue;
setSelectedBoat(thisYacht); setSelectedBoat(thisYacht);
}
}); });
} }
/**
* Generates time line for each boat, and stores time time into timelineInfos hash map
*/
private void initializeTimelines() {
HashMap<Yacht, List> boat_events = race.getEvents();
for (Yacht boat : boat_events.keySet()) {
startingBoats.add(boat);
// // x, y are the real time coordinates
// DoubleProperty x = new SimpleDoubleProperty();
// DoubleProperty y = new SimpleDoubleProperty();
//
// List<KeyFrame> keyFrames = new ArrayList<>();
// List<Event> events = boat_events.get(boat);
//
// // iterates all events and convert each event to keyFrame, then add them into a list
// for (Event event : events) {
// if (event.getIsFinishingEvent()) {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished -> {race.setBoatFinished(boat); handleEvent(event);},
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// } else {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished ->{
// handleEvent(event);
// boat.setHeading(event.getBoatHeading());
// },
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// }
// }
// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y));
}
setRaceDuration();
}
private void setRaceDuration(){
Double maxDuration = 0.0;
Timeline maxTimeline = null;
for (TimelineInfo timelineInfo : timelineInfos.values()) {
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getTotalDuration().toMillis() >= maxDuration) {
maxDuration = timeline.getTotalDuration().toMillis();
maxTimeline = timeline;
}
// Timelines are paused by default
timeline.play();
timeline.pause();
}
maxTimeline.setOnFinished(event -> {
race.setRaceFinished();
loadRaceResultView();
});
}
/**
* Play each boats timerTimeline
*/
public void playTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.PAUSED){
timeline.play();
}
}
}
/**
* Pause each boats timerTimeline
*/
public void pauseTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.RUNNING){
timeline.pause();
}
}
}
/** /**
* Display the list of boats in the order they finished the race * Display the list of boats in the order they finished the race
@@ -342,46 +286,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
public void handleEvent(Event event) {
Yacht boat = event.getBoat();
boatOrder.remove(boat);
boat.setMarkLastPast(event.getMarkPosInRace());
boatOrder.add(boat);
boatOrder.sort(new Comparator<Yacht>() {
@Override
public int compare(Yacht b1, Yacht b2) {
return b2.getMarkLastPast() - b1.getMarkLastPast();
}
});
showOrder();
}
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"));
// }
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else {
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
}
/** /**
* Convert seconds to a string of the format mm:ss * Convert seconds to a string of the format mm:ss
@@ -396,7 +300,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return String.format("%02d:%02d", time / 60, time % 60); return String.format("%02d:%02d", time / 60, time % 60);
} }
private String currentTimer() { private String getTimeSinceStartOfRace() {
String timerString = "0:00"; String timerString = "0:00";
if (StreamParser.getTimeSinceStart() > 0) { if (StreamParser.getTimeSinceStart() > 0) {
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60); String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
@@ -416,12 +320,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return timerString; return timerString;
} }
public void stopTimer() {
timerTimeline.stop();
}
public void startTimer() {
timerTimeline.play();
}
public boolean isDisplayFps() { public boolean isDisplayFps() {
return displayFps; return displayFps;
@@ -431,13 +329,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return race; return race;
} }
public Map<Yacht, TimelineInfo> getTimelineInfos() {
return timelineInfos;
}
public ArrayList<Yacht> getStartingBoats(){
return startingBoats;
}
/** /**
* Display the important annotations for a specific BoatGroup * Display the important annotations for a specific BoatGroup
@@ -524,6 +415,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup. //are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
if (bg.getBoat().getHullID().equals(yacht.getHullID())) { if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
bg.setIsSelected(true); bg.setIsSelected(true);
selectedBoat = yacht;
} else { } else {
bg.setIsSelected(false); bg.setIsSelected(false);
} }
@@ -1,6 +1,7 @@
package seng302.models.mark; package seng302.models.mark;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.CacheHint;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
@@ -24,7 +24,6 @@ import java.util.concurrent.PriorityBlockingQueue;
* and parsed in by turning the byte arrays into useful data. There are two public static hashmaps * and parsed in by turning the byte arrays into useful data. There are two public static hashmaps
* that are threadsafe so the visualiser can always access the latest speed and position available * that are threadsafe so the visualiser can always access the latest speed and position available
* Created by kre39 on 23/04/17. * Created by kre39 on 23/04/17.
*
*/ */
public class StreamParser extends Thread{ public class StreamParser extends Thread{