Fixed errors in making the keybinding replaceable.

- Changed KeyFactory to not be a singleton
- Simplified keyBindings initializer
- Modified and simplified keyListener
- Added method to copy existing keyState
- Changed button events
- Changed to newer lambda functions
- Modified updateKey method
- Left option for multiple keys bound to one command
- Updated and wrote new JavaDoc

#story[1197]
main
Jessica Syder 8 years ago
parent 8250226bde
commit 2188ddc3a3

@ -1,9 +1,6 @@
package visualiser.Controllers; package visualiser.Controllers;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ListView; import javafx.scene.control.ListView;
@ -11,25 +8,40 @@ import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory; import visualiser.gameController.Keys.KeyFactory;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static visualiser.app.App.keyFactory;
/** /**
* Controller for the scene used to display and update current key bindings. * Controller for the scene used to display and update current key bindings.
*/ */
public class KeyBindingsController { public class KeyBindingsController {
@FXML Button btnSave; private @FXML Button btnSave;
@FXML Button btnCancel; private @FXML Button btnCancel;
@FXML Button btnReset; private @FXML Button btnReset;
@FXML ListView lstControl; private @FXML ListView lstControl;
@FXML ListView lstKey; private @FXML ListView lstKey;
@FXML ListView lstDescription; private @FXML ListView lstDescription;
@FXML AnchorPane anchor; private @FXML AnchorPane anchor;
String currentButton = null; private Button currentButton = null;
KeyFactory keyFactory = KeyFactory.getFactory(); private KeyFactory newKeyFactory;
public void initialize(){ public void initialize(){
// create new key factory to modify, keeping the existing one safe
newKeyFactory = copyExistingFactory();
initializeTable();
populateTable();
setKeyListener();
}
// headings for each column /**
* Sets up table before populating it.
* Set up includes headings, CSS styling and modifying default properties.
*/
public void initializeTable(){
// set the headings for each column
lstKey.getItems().add("Key"); lstKey.getItems().add("Key");
lstControl.getItems().add("Command"); lstControl.getItems().add("Command");
lstDescription.getItems().add("Description"); lstDescription.getItems().add("Description");
@ -37,47 +49,6 @@ public class KeyBindingsController {
lstControl.getSelectionModel().select(0); lstControl.getSelectionModel().select(0);
lstDescription.getSelectionModel().select(0); lstDescription.getSelectionModel().select(0);
// populate columns with current key bindings and buttons to update
for (Map.Entry<String, ControlKey> entry : keyFactory.getKeyState().entrySet()) {
Button button = new Button(entry.getKey());
button.setMinWidth(120);
button.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent e) {
currentButton = button.getText();
System.out.println("Button clicked");
}
});
lstKey.getItems().add(button);
lstControl.getItems().add(entry.getValue());
lstDescription.getItems().add(entry.getValue().getProtocolCode());
}
// stop the columns from being selectable, so only the buttons are
lstKey.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) -> {
Platform.runLater(new Runnable() {
public void run() {
lstKey.getSelectionModel().select(0);
}
});
});
lstDescription.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) -> {
Platform.runLater(new Runnable() {
public void run() {
lstDescription.getSelectionModel().select(0);
}
});
});
lstControl.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) -> {
Platform.runLater(new Runnable() {
public void run() {
lstControl.getSelectionModel().select(0);
}
});
});
// add CSS stylesheet once the scene has been created // add CSS stylesheet once the scene has been created
lstKey.sceneProperty().addListener((obs, oldScene, newScene) -> { lstKey.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) { if (newScene != null) {
@ -85,7 +56,54 @@ public class KeyBindingsController {
} }
}); });
setKeyListener(); // stop the columns from being selectable, so only the buttons are
lstKey.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) ->
Platform.runLater(() ->
lstKey.getSelectionModel().select(0)));
lstDescription.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) ->
Platform.runLater(() ->
lstDescription.getSelectionModel().select(0)));
lstControl.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newValue) ->
Platform.runLater(() ->
lstControl.getSelectionModel().select(0)));
}
/**
* Populates the table with commands and their key binding details.
*/
public void populateTable(){
// add each command to the table
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet()) {
// create button for command
Button button = new Button(entry.getKey());
button.setMinWidth(120);
button.setId(entry.getValue().toString());
button.setOnAction(e -> currentButton = button);
// display details for command in table
lstControl.getItems().add(entry.getValue());
lstKey.getItems().add(button);
lstDescription.getItems().add(entry.getValue().getProtocolCode());
}
}
/**
* Makes a copy of the keyfactory that does not modify the original.
* @return new keyfactory to be modified
*/
public KeyFactory copyExistingFactory(){
newKeyFactory = new KeyFactory();
Map<String, ControlKey> newKeyState = newKeyFactory.getKeyState();
Map<String, ControlKey> oldKeyState = keyFactory.getKeyState();
newKeyState = new HashMap<>(); // clear default keys
// copy over commands and their keys
for (Map.Entry<String, ControlKey> entry : oldKeyState.entrySet()){
newKeyState.put(entry.getKey(), entry.getValue());
}
return newKeyFactory;
} }
/** /**
@ -96,17 +114,12 @@ public class KeyBindingsController {
anchor.addEventFilter(KeyEvent.KEY_PRESSED, event -> { anchor.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
// if a button was clicked // if a button was clicked
if (currentButton != null) { if (currentButton != null) {
System.out.println("button is clicked");
// update text on the button // update text on the button
ObservableList buttons = lstKey.getItems(); currentButton.setText(event.getCode().toString());
for (int i = 1; i < buttons.size(); i++) {
if (currentButton == ((Button)buttons.get(i)).getText()) {
((Button)buttons.get(i)).setText(event.getCode().toString
());
break;
}
}
// update the control key // update the control key
keyFactory.updateKey(currentButton, event.getCode().toString()); newKeyFactory.updateKey(event.getCode().toString(),
currentButton.getId());
// remove current button selection // remove current button selection
currentButton = null; currentButton = null;
} }

@ -10,7 +10,6 @@ import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
@ -23,7 +22,6 @@ import shared.model.Leg;
import visualiser.app.App; import visualiser.app.App;
import visualiser.gameController.ControllerClient; import visualiser.gameController.ControllerClient;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory;
import visualiser.model.*; import visualiser.model.*;
import java.io.IOException; import java.io.IOException;
@ -33,6 +31,7 @@ import java.util.ResourceBundle;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import static visualiser.app.App.keyFactory;
/** /**
@ -113,7 +112,7 @@ public class RaceController extends Controller {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
KeyFactory keyFactory = KeyFactory.getFactory(); // KeyFactory keyFactory = KeyFactory.getFactory();
infoTableShow = true; infoTableShow = true;
// Initialise keyboard handler // Initialise keyboard handler

@ -27,6 +27,7 @@ import javafx.stage.StageStyle;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
import javafx.util.Duration; import javafx.util.Duration;
import visualiser.Controllers.MainController; import visualiser.Controllers.MainController;
import visualiser.gameController.Keys.KeyFactory;
public class App extends Application { public class App extends Application {
@ -37,6 +38,7 @@ public class App extends Application {
private Label progressText; private Label progressText;
private static final int SPLASH_WIDTH = 676; private static final int SPLASH_WIDTH = 676;
private static final int SPLASH_HEIGHT = 227; private static final int SPLASH_HEIGHT = 227;
public static KeyFactory keyFactory = new KeyFactory();
public static App app; public static App app;

@ -3,10 +3,11 @@ package visualiser.gameController;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.scene.Scene; import javafx.scene.Scene;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory;
import java.util.HashMap; import java.util.HashMap;
import static visualiser.app.App.keyFactory;
/** /**
* Class for checking what keys are currently being used * Class for checking what keys are currently being used
*/ */
@ -18,7 +19,7 @@ public class InputChecker {
* @param scene Scene the controller is to run in parallel with. * @param scene Scene the controller is to run in parallel with.
*/ */
public void runWithScene(Scene scene){ public void runWithScene(Scene scene){
KeyFactory keyFactory = KeyFactory.getFactory(); // KeyFactory keyFactory = KeyFactory.getFactory();
scene.setOnKeyPressed(event -> { scene.setOnKeyPressed(event -> {
String codeString = event.getCode().toString(); String codeString = event.getCode().toString();

@ -9,11 +9,9 @@ public class DownWindKey extends ControlKey {
/** /**
* Constructor for Control * Constructor for Control
* @param name name of the key
*
*/ */
public DownWindKey(String name) { public DownWindKey() {
super(name, BoatActionEnum.DOWNWIND); super("Downwind", BoatActionEnum.DOWNWIND);
} }
@Override @Override

@ -13,30 +13,17 @@ public class KeyFactory {
private Map<String, ControlKey> keyState; private Map<String, ControlKey> keyState;
/** /**
* Singleton instance to enforce consistent key state * Constructor for key state, set up initial state of each action.
*/ */
private static KeyFactory theFactory = new KeyFactory(); public KeyFactory() {
/**
* Singleton constructor for key state, set up initial state of each action.
*/
private KeyFactory() {
this.keyState = new HashMap<>(); this.keyState = new HashMap<>();
keyState.put("Z", new ZoomInKey("Zoom In")); keyState.put("Z", new ZoomInKey());
keyState.put("X", new ZoomOutKey("Zoom Out")); keyState.put("X", new ZoomOutKey());
keyState.put("SPACE", new VMGKey("VMG")); keyState.put("SPACE", new VMGKey());
keyState.put("SHIFT", new SailsToggleKey("Toggle Sails")); keyState.put("SHIFT", new SailsToggleKey());
keyState.put("ENTER", new TackGybeKey("Tack/Gybe")); keyState.put("ENTER", new TackGybeKey());
keyState.put("UP", new UpWindKey("Upwind")); keyState.put("UP", new UpWindKey());
keyState.put("DOWN", new DownWindKey("Downwind")); keyState.put("DOWN", new DownWindKey());
}
/**
* Get singleton instance of KeyFactory to interact with key state
* @return automatically constructed KeyFactory
*/
public static KeyFactory getFactory() {
return theFactory;
} }
/** /**
@ -54,12 +41,21 @@ public class KeyFactory {
/** /**
* Update the key bound to a particular command in the keystate. * Update the key bound to a particular command in the keystate.
* @param oldKey the existing key to updated * @param newKey the new key value for the command
* @param newKey the new key value to replace the old * @param command the command to be updated
*/ */
public void updateKey(String oldKey, String newKey){ public void updateKey(String newKey, String command){
ControlKey controlKey = keyState.get(oldKey); ControlKey controlKey = null;
String oldKey = null;
for (Map.Entry<String, ControlKey> entry : keyState.entrySet()) {
// if this is the correct command
if (entry.getValue().toString()==command){
controlKey = entry.getValue();
oldKey = entry.getKey();
}
}
keyState.remove(oldKey, controlKey); keyState.remove(oldKey, controlKey);
keyState.put(newKey, controlKey); keyState.put(newKey, controlKey);
} }
} }

@ -10,11 +10,9 @@ public class SailsToggleKey extends ControlKey {
/** /**
* Constructor for Control * Constructor for Control
* @param name name of the key
*
*/ */
public SailsToggleKey(String name) { public SailsToggleKey() {
super(name, BoatActionEnum.NOT_A_STATUS); super("Toggle Sails", BoatActionEnum.NOT_A_STATUS);
} }
/** /**

@ -9,11 +9,9 @@ public class TackGybeKey extends ControlKey {
/** /**
* Constructor for Control * Constructor for Control
* @param name name of the key
*
*/ */
public TackGybeKey(String name) { public TackGybeKey() {
super(name, BoatActionEnum.TACK_GYBE); super("Tack/Gybe", BoatActionEnum.TACK_GYBE);
} }
@Override @Override

@ -9,11 +9,9 @@ public class UpWindKey extends ControlKey {
/** /**
* Constructor for Control * Constructor for Control
* @param name name of the key
*
*/ */
public UpWindKey(String name) { public UpWindKey() {
super(name, BoatActionEnum.UPWIND); super("Upwind", BoatActionEnum.UPWIND);
} }
@Override @Override

@ -1,6 +1,5 @@
package visualiser.gameController.Keys; package visualiser.gameController.Keys;
import javafx.scene.input.KeyCode;
import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatActionEnum;
/** /**
@ -10,11 +9,9 @@ public class VMGKey extends ControlKey{
/** /**
* Constructor for Control * Constructor for Control
*
* @param name name of the key
*/ */
public VMGKey(String name) { public VMGKey() {
super(name, BoatActionEnum.AUTO_PILOT); super("VMG", BoatActionEnum.AUTO_PILOT);
} }
@Override @Override

@ -5,8 +5,8 @@ package visualiser.gameController.Keys;
*/ */
public class ZoomInKey extends ControlKey { public class ZoomInKey extends ControlKey {
public ZoomInKey(String name) { public ZoomInKey() {
super(name); super("Zoom In");
} }
@Override @Override

@ -7,11 +7,9 @@ public class ZoomOutKey extends ControlKey{
/** /**
* Constructor for Control * Constructor for Control
* @param name name of the key
*
*/ */
public ZoomOutKey(String name) { public ZoomOutKey() {
super(name); super("Zoom Out");
} }
@Override @Override

Loading…
Cancel
Save