User can save, reset or cancel.

- Created a notification popups for errors
- Added functionality to save, cancel and reset buttons
- Key bindings are only saved if they're valid
- Added window close event
- Can not exit without saving correctly
- CSS to cancel, save and reset buttons to differentiate between key buttons
- Javadocd

#story[1197]
main
Jessica Syder 8 years ago
parent 086206a623
commit 3fdfbd83e0

@ -2,14 +2,20 @@ package visualiser.Controllers;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ListView; import javafx.scene.control.ListView;
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;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory; import visualiser.gameController.Keys.KeyFactory;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -26,8 +32,9 @@ public class KeyBindingsController {
private @FXML ListView lstKey; private @FXML ListView lstKey;
private @FXML ListView lstDescription; private @FXML ListView lstDescription;
private @FXML AnchorPane anchor; private @FXML AnchorPane anchor;
private Button currentButton = null; private Button currentButton = null; // last button clicked
private KeyFactory newKeyFactory; private KeyFactory newKeyFactory;
private Boolean changed = false; // keybindings have been modified
public void initialize(){ public void initialize(){
// create new key factory to modify, keeping the existing one safe // create new key factory to modify, keeping the existing one safe
@ -96,14 +103,14 @@ public class KeyBindingsController {
*/ */
public KeyFactory copyExistingFactory(){ public KeyFactory copyExistingFactory(){
newKeyFactory = new KeyFactory(); newKeyFactory = new KeyFactory();
Map<String, ControlKey> newKeyState = newKeyFactory.getKeyState();
Map<String, ControlKey> oldKeyState = keyFactory.getKeyState(); Map<String, ControlKey> oldKeyState = keyFactory.getKeyState();
newKeyState = new HashMap<>(); // clear default keys Map<String, ControlKey> newKeyState = new HashMap<>();
// copy over commands and their keys // copy over commands and their keys
for (Map.Entry<String, ControlKey> entry : oldKeyState.entrySet()){ for (Map.Entry<String, ControlKey> entry : oldKeyState.entrySet()){
newKeyState.put(entry.getKey(), entry.getValue()); newKeyState.put(entry.getKey(), entry.getValue());
} }
newKeyFactory.setKeyState(newKeyState);
return newKeyFactory; return newKeyFactory;
} }
@ -137,14 +144,20 @@ public class KeyBindingsController {
currentButton.getId()); currentButton.getId());
// remove current button selection // remove current button selection
currentButton = null; currentButton = null;
changed = true;
btnCancel.requestFocus(); btnCancel.requestFocus();
} }
event.consume(); event.consume();
}); });
} }
/**
* Cancel and exits the key bindings menu. Changes are not forced to be
* saved or fixed if invalid, and instead are defaulted back to the last
* successful saved state.
*/
public void cancel(){ public void cancel(){
System.out.println("cancel clicked"); ((Stage)btnCancel.getScene().getWindow()).close();
} }
/** /**
@ -157,13 +170,76 @@ public class KeyBindingsController {
newKeyFactory = new KeyFactory(); newKeyFactory = new KeyFactory();
initializeTable(); initializeTable();
populateTable(); populateTable();
changed = true;
} }
/** /**
* Replace existing {@link KeyFactory} with the modified key bindings. * Replace existing {@link KeyFactory} with the modified key bindings.
*/ */
public void save(){ public void save(){
keyFactory = newKeyFactory; if (isFactoryValid()) {
keyFactory = newKeyFactory;
newKeyFactory = new KeyFactory();
changed = false;
loadNotification("Key bindings were successfully saved.", false);
} else {
loadNotification("One or more key bindings are missing. " +
"Failed to save.", true);
}
}
/**
* Checks the {@link KeyFactory} being modified is valid and that no
* commands are missing a key binding.
* @return True if valid, false if invalid
*/
public Boolean isFactoryValid(){
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet
()) {
if (entry.getKey().toString()==entry.getValue().toString()){
return false;
}
}
return true;
}
/**
* Method used to stop a user from exiting key bindings without saving
* their changes to the {@link KeyFactory}.
* @param we {@link WindowEvent} close request to be consumed if settings
* have not been successfully saved.
*/
public void onExit(WindowEvent we){
// if modified KeyFactory hasn't been saved
if (keyFactory!=newKeyFactory && changed==true){
loadNotification("Please cancel or save your changes before exiting" +
".", true);
we.consume();
}
}
/**
* Loads a popup window giving confirmation/warning of user activity.
* @param message the message to be displayed to the user
* @param warning true if the message to be displayed is due to user error
*/
public void loadNotification(String message, Boolean warning){
Parent root = null;
FXMLLoader loader = new FXMLLoader(getClass().getResource
("/visualiser/scenes/notification.fxml"));
try {
root = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
NotificationController controller = loader.getController();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.centerOnScreen();
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
// displays given message in the window
controller.setMessage(message, warning);
} }
} }

@ -0,0 +1,35 @@
package visualiser.Controllers;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
/**
* Controller for a popup notification regarding user activity.
*/
public class NotificationController {
private @FXML Label lblDescription;
private @FXML Text txtMessage;
/**
* Closes the popup window once clicked.
*/
public void ok(){
((Stage)lblDescription.getScene().getWindow()).close();
}
/**
* Displays the appropriate popup notification.
* @param message message for the user
* @param warning if true warning text shown, if false success text shown
*/
public void setMessage(String message, Boolean warning){
lblDescription.setText(message);
if (!warning){
txtMessage.setText("Success!");
txtMessage.setFill(Color.GREEN);
}
}
}

@ -1,5 +1,6 @@
package visualiser.Controllers; package visualiser.Controllers;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
@ -9,6 +10,7 @@ import javafx.scene.control.RadioButton;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality; import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import visualiser.app.App; import visualiser.app.App;
import java.io.IOException; import java.io.IOException;
@ -88,6 +90,22 @@ public class TitleController extends Controller {
* Called when control button is pressed. New pop up window displaying controls * Called when control button is pressed. New pop up window displaying controls
*/ */
public void controlBtnPressed(){ public void controlBtnPressed(){
// Parent root2 = loader2.load();
// KeyBindingsController controller = loader2.getController();
// Stage stage2 = new Stage();
// stage2.setScene(new Scene(root2));
// stage2.centerOnScreen();
// stage2.initModality(Modality.APPLICATION_MODAL);
// stage2.show();
// stage2.setOnCloseRequest(new EventHandler<WindowEvent>() {
// public void handle(WindowEvent we) {
// if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) {
// controller.onExit(we);
// }
// }
// });
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml")); loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml"));
Parent layout; Parent layout;
@ -100,6 +118,14 @@ public class TitleController extends Controller {
popupStage.initModality(Modality.WINDOW_MODAL); popupStage.initModality(Modality.WINDOW_MODAL);
popupStage.setScene(scene); popupStage.setScene(scene);
popupStage.showAndWait(); popupStage.showAndWait();
KeyBindingsController controller = loader.getController();
popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) {
controller.onExit(we);
}
}
});
} catch (Exception e){ } catch (Exception e){
e.printStackTrace(); e.printStackTrace();
} }

@ -39,6 +39,10 @@ public class KeyFactory {
return keyState; return keyState;
} }
public void setKeyState(Map<String, ControlKey> keyState) {
this.keyState = keyState;
}
/** /**
* Update the key bound to a particular command in the keystate. * Update the key bound to a particular command in the keystate.
* @param newKey the new key value for the command * @param newKey the new key value for the command

@ -23,6 +23,7 @@
-fx-text-fill: #242d35; -fx-text-fill: #242d35;
-fx-font-size: 12px; -fx-font-size: 12px;
-fx-font-family: "Courier New"; -fx-font-family: "Courier New";
-fx-border-color: #a9c8ff;
} }
.button:focused { .button:focused {
@ -32,4 +33,13 @@
#anchor { #anchor {
-fx-background-color: #fdfac3; -fx-background-color: #fdfac3;
}
#menu{
-fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%);
-fx-background-radius: 4px;
-fx-border-radius: 4px;
-fx-text-fill: #242d35;
-fx-font-size: 12px;
-fx-font-family: "Verdana";
-fx-border-color: #a9c8ff;
} }

@ -13,11 +13,12 @@
<Font name="Comic Sans MS" size="44.0" /> <Font name="Comic Sans MS" size="44.0" />
</font> </font>
</Label> </Label>
<Button fx:id="btnCancel" layoutX="430.0" layoutY="428.0" mnemonicParsing="false" onAction="#cancel" prefWidth="160.0" text="Cancel" AnchorPane.bottomAnchor="18.0" AnchorPane.rightAnchor="20.0" /> <Button id="menu" fx:id="btnCancel" layoutX="430.0" layoutY="428.0"
mnemonicParsing="false" onAction="#cancel" prefWidth="160.0" text="Cancel" AnchorPane.bottomAnchor="18.0" AnchorPane.rightAnchor="20.0" />
<ListView fx:id="lstControl" focusTraversable="false" layoutX="27.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" /> <ListView fx:id="lstControl" focusTraversable="false" layoutX="27.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
<ListView fx:id="lstKey" focusTraversable="false" layoutX="176.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" /> <ListView fx:id="lstKey" focusTraversable="false" layoutX="176.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
<ListView fx:id="lstDescription" focusTraversable="false" layoutX="325.0" layoutY="88.0" prefHeight="322.0" prefWidth="250.0" /> <ListView fx:id="lstDescription" focusTraversable="false" layoutX="325.0" layoutY="88.0" prefHeight="322.0" prefWidth="250.0" />
<Button fx:id="btnSave" layoutX="220.0" layoutY="428.0" mnemonicParsing="false" onAction="#save" prefWidth="160.0" text="Save" AnchorPane.bottomAnchor="18.0" /> <Button id="menu" fx:id="btnSave" layoutX="220.0" layoutY="428.0" mnemonicParsing="false" onAction="#save" prefWidth="160.0" text="Save" AnchorPane.bottomAnchor="18.0" />
<Button fx:id="btnReset" layoutX="20.0" layoutY="428.0" mnemonicParsing="false" onAction="#reset" prefWidth="160.0" text="Reset to Default" AnchorPane.bottomAnchor="18.0" AnchorPane.leftAnchor="20.0" /> <Button id="menu" fx:id="btnReset" layoutX="20.0" layoutY="428.0" mnemonicParsing="false" onAction="#reset" prefWidth="160.0" text="Reset to Default" AnchorPane.bottomAnchor="18.0" AnchorPane.leftAnchor="20.0" />
</children> </children>
</AnchorPane> </AnchorPane>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.NotificationController">
<children>
<Button fx:id="btnOk" layoutX="110.0" layoutY="65.0" mnemonicParsing="false" onAction="#ok" prefWidth="80.0" text="Ok" />
<Text fx:id="txtMessage" fill="RED" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Warning!" textAlignment="CENTER" wrappingWidth="300.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Text>
<Label fx:id="lblDescription" alignment="CENTER" layoutY="36.0" prefHeight="17.0" prefWidth="300.0" textAlignment="CENTER" />
</children>
</Pane>
Loading…
Cancel
Save