diff --git a/src/main/java/es/kauron/jstudy/controller/Controller.java b/src/main/java/es/kauron/jstudy/controller/Controller.java index d48c325..ba8c9a8 100644 --- a/src/main/java/es/kauron/jstudy/controller/Controller.java +++ b/src/main/java/es/kauron/jstudy/controller/Controller.java @@ -2,9 +2,12 @@ package es.kauron.jstudy.controller; import es.kauron.jstudy.Main; import es.kauron.jstudy.model.TestItem; +import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.event.ActionEvent; +import javafx.event.Event; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; @@ -24,22 +27,25 @@ public class Controller implements Initializable { @FXML private BorderPane root; - @FXML - private ToolBar toolbar; - @FXML - private MenuItem saveMenu; private BooleanProperty table = new SimpleBooleanProperty(false); private Map tabMap = new HashMap<>(); @Override public void initialize(URL url, ResourceBundle resourceBundle) { - tabPane.getSelectionModel().selectedItemProperty().addListener((change, o, n) -> { - if (tabMap.get(n) != null) { - table.set(true); - } else table.set(false); - }); - saveMenu.disableProperty().bind(table.not()); + tabPane.getSelectionModel().selectedItemProperty().addListener((ob, o, n) -> table.set(tabMap.get(n) != null)); + Platform.runLater(() -> + root.getScene().getWindow().setOnCloseRequest(event -> { + for (Tab tab : tabPane.getTabs()) { + EventHandler handler = tab.getOnCloseRequest(); + if (tab.isClosable() && handler != null) { + tabPane.getSelectionModel().select(tab); + handler.handle(event); + if (event.isConsumed()) return; + } + } + }) + ); } @FXML @@ -63,7 +69,7 @@ public class Controller implements Initializable { dialog.showAndWait(); dialog.setResultConverter(value -> value.getButtonData().equals(ButtonBar.ButtonData.OK_DONE) ? value.getText() : ""); if (dialog.getResult() == null || dialog.getResult().isEmpty()) return; - tabPane.getTabs().add(createTableTab(dialog.getResult(), new ArrayList<>())); + tabPane.getTabs().add(createTableTab(dialog.getResult(), new ArrayList<>(), null)); tabPane.getSelectionModel().selectLast(); } @@ -75,20 +81,11 @@ public class Controller implements Initializable { if (file == null) return; List aux = TestItem.loadFrom(file, TestItem.COLONS); if (aux != null) { - tabPane.getTabs().add(createTableTab(file.getName().substring(0, file.getName().lastIndexOf('.')), aux)); + tabPane.getTabs().add(createTableTab(file.getName().substring(0, file.getName().lastIndexOf('.')), aux, file)); tabPane.getSelectionModel().selectLast(); } } - @FXML - private void onSaveAction(ActionEvent event) { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JStudy file", "*.jsdb")); - File file = chooser.showSaveDialog(root.getScene().getWindow()); - if (file == null) return; - TestItem.saveTo(file, tabMap.get(tabPane.getSelectionModel().getSelectedItem()).getData()); - } - @FXML private void onImportAction(ActionEvent event) { FileChooser chooser = new FileChooser(); @@ -104,22 +101,37 @@ public class Controller implements Initializable { separator = TestItem.COMMA; List aux = TestItem.loadFrom(file, separator); if (aux != null) { - tabPane.getTabs().add(createTableTab(file.getName().substring(0, file.getName().lastIndexOf('.')), aux)); + tabPane.getTabs().add(createTableTab(file.getName().substring(0, file.getName().lastIndexOf('.')), aux, null)); tabPane.getSelectionModel().selectLast(); } } - private Tab createTableTab(String name, List list) { + private Tab createTableTab(String name, List list, File file) { try { Tab tab = new Tab(name); FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/table.fxml")); Parent tableRoot = loader.load(); - ((TableController) loader.getController()).setData(list, this); + ((TableController) loader.getController()).setData(list, this, file); tabMap.put(tab, loader.getController()); tab.setContent(tableRoot); + tab.setOnCloseRequest(event -> { + if (!((TableController) loader.getController()).saved.get()) { + Alert dialog = new Alert(Alert.AlertType.WARNING); + dialog.setHeaderText("The tab " + name + " has unsaved information"); + dialog.setContentText("Do you want to save those changes?"); + dialog.getButtonTypes().clear(); + dialog.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); + dialog.showAndWait(); + if (dialog.getResult().equals(ButtonType.YES)) { + ((TableController) loader.getController()).onSaveAction(null); + } else if (dialog.getResult().equals(ButtonType.CANCEL)) { + event.consume(); + } + } + }); return tab; } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/es/kauron/jstudy/controller/EditController.java b/src/main/java/es/kauron/jstudy/controller/EditController.java index 27b3c73..f68e747 100644 --- a/src/main/java/es/kauron/jstudy/controller/EditController.java +++ b/src/main/java/es/kauron/jstudy/controller/EditController.java @@ -1,6 +1,7 @@ package es.kauron.jstudy.controller; import es.kauron.jstudy.model.TestItem; +import javafx.beans.property.BooleanProperty; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; @@ -18,18 +19,21 @@ public class EditController implements Initializable { private ObservableList list; private int index; private TestItem item; + private BooleanProperty saved; + private String originalQuestion, originalAnswer; @Override public void initialize(URL url, ResourceBundle rb) { } - protected void setList(ObservableList list) { - setList(list, -1); + protected void setList(ObservableList list, BooleanProperty saved) { + setList(list, -1, saved); } - protected void setList(ObservableList list, int index) { + protected void setList(ObservableList list, int index, BooleanProperty saved) { this.list = list; // Save attributes correctly this.index = index; + this.saved = saved; // Copy current values to textViews // and initialize item to hold the current object in edition if (index < 0) item = new TestItem("",""); @@ -38,12 +42,14 @@ public class EditController implements Initializable { answerText.setText(list.get(index).getAnswer()); item = new TestItem(list.get(index)); } + originalQuestion = questionText.getText(); + originalAnswer = answerText.getText(); item.questionProperty().bind(questionText.textProperty()); item.answerProperty().bind(answerText.textProperty()); } @FXML - private void onSaveAction(ActionEvent event) { + protected void onSaveAction(ActionEvent event) { if (index < 0) { if (!item.isValid()) return; @@ -51,11 +57,12 @@ public class EditController implements Initializable { } else { list.set(index, item); } + if (!originalQuestion.equals(item.getQuestion()) || !originalAnswer.equals(item.getAnswer())) saved.set(false); onCancelAction(event); } @FXML - private void onCancelAction(ActionEvent event) { + protected void onCancelAction(ActionEvent event) { ((Stage) ((Node) event.getSource()) .getScene().getWindow()) .close(); diff --git a/src/main/java/es/kauron/jstudy/controller/TableController.java b/src/main/java/es/kauron/jstudy/controller/TableController.java index 40453fa..5865126 100644 --- a/src/main/java/es/kauron/jstudy/controller/TableController.java +++ b/src/main/java/es/kauron/jstudy/controller/TableController.java @@ -2,7 +2,10 @@ package es.kauron.jstudy.controller; import es.kauron.jstudy.Main; import es.kauron.jstudy.model.TestItem; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; @@ -14,9 +17,11 @@ import javafx.scene.control.Button; import javafx.scene.control.SelectionMode; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; +import javafx.stage.FileChooser; import javafx.stage.Modality; import javafx.stage.Stage; +import java.io.File; import java.io.IOException; import java.net.URL; import java.util.List; @@ -28,42 +33,55 @@ public class TableController implements Initializable { @FXML private TableColumn answerCol, questionCol; @FXML - private Button editButton, duplicateButton, swapButton, testSelectionButton, deleteButton; + private Button editButton, duplicateButton, swapButton, testSelectionButton, deleteButton, saveButton; private ObservableList data; private Controller parent; + private File file; + protected BooleanProperty saved = new SimpleBooleanProperty(); @Override public void initialize(URL url, ResourceBundle resourceBundle) { table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); answerCol.setCellValueFactory(e -> e.getValue().answerProperty()); questionCol.setCellValueFactory(e -> e.getValue().questionProperty()); - bindButtons(); + table.getSelectionModel().getSelectedIndices().addListener((ListChangeListener) obs -> { + editButton.setDisable(obs.getList().size() != 1); + swapButton.setDisable(obs.getList().size() < 1); + deleteButton.setDisable(obs.getList().size() < 1); + duplicateButton.setDisable(obs.getList().size() < 1); + testSelectionButton.setDisable(obs.getList().size() < 1); + }); + saveButton.disableProperty().bind(saved); } - private void bindButtons() { - editButton.disableProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0)); - swapButton.disableProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0)); - deleteButton.disableProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0)); - duplicateButton.disableProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0)); - testSelectionButton.disableProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0)); - } - - void setData(List list, Controller controller) { + void setData(List list, Controller controller, File file) { this.data = FXCollections.observableArrayList(list); this.parent = controller; table.setItems(data); + this.file = file; + saved.set(file != null); } - List getData() {return data;} + @FXML + protected void onSaveAction(ActionEvent event) { + if (file == null) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JStudy file", "*.jsdb")); + file = chooser.showSaveDialog(table.getScene().getWindow()); + } + if (file == null) return; + TestItem.saveTo(file, data); + saved.set(true); + } @FXML - private void onAddAction(ActionEvent event) { + protected void onAddAction(ActionEvent event) { try { FXMLLoader cargador = new FXMLLoader(Main.class.getResource("view/edit.fxml")); Parent pRoot = cargador.load(); - ((EditController) cargador.getController()).setList(data); + ((EditController) cargador.getController()).setList(data, saved); Stage stage = new Stage(); stage.setTitle("New entry"); @@ -76,7 +94,7 @@ public class TableController implements Initializable { } @FXML - private void onEditAction(ActionEvent event) { + protected void onEditAction(ActionEvent event) { ObservableList list = table.getSelectionModel().getSelectedIndices(); if (list.size() != 1) return; int index = list.get(0); @@ -84,7 +102,7 @@ public class TableController implements Initializable { FXMLLoader cargador = new FXMLLoader(Main.class.getResource("view/edit.fxml")); Parent root = cargador.load(); - ((EditController) cargador.getController()).setList(table.getItems(), index); + ((EditController) cargador.getController()).setList(table.getItems(), index, saved); Stage stage = new Stage(); stage.setTitle("Editing entry..."); @@ -97,7 +115,8 @@ public class TableController implements Initializable { } @FXML - private void onSwapAction(ActionEvent event) { + protected void onSwapAction(ActionEvent event) { + if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (TestItem item : table.getSelectionModel().getSelectedItems()) { String question = item.getQuestion(); item.questionProperty().set(item.getAnswer()); @@ -107,26 +126,28 @@ public class TableController implements Initializable { } @FXML - private void onDuplicateAction(ActionEvent event) { + protected void onDuplicateAction(ActionEvent event) { + if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (int i : table.getSelectionModel().getSelectedIndices()) table.getItems().add(new TestItem(table.getItems().get(i))); table.requestFocus(); } @FXML - private void onDeleteAction(ActionEvent event) { + protected void onDeleteAction(ActionEvent event) { + if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (int i : table.getSelectionModel().getSelectedIndices()) table.getItems().remove(i); table.requestFocus(); } @FXML - private void onTestSelectionAction(ActionEvent event) { + protected void onTestSelectionAction(ActionEvent event) { parent.newTest(table.getSelectionModel().getSelectedItems()); } @FXML - private void onTestAction(ActionEvent event) { + protected void onTestAction(ActionEvent event) { parent.newTest(data); } } diff --git a/src/main/resources/es/kauron/jstudy/view/main.fxml b/src/main/resources/es/kauron/jstudy/view/main.fxml index db2e51d..30607cd 100644 --- a/src/main/resources/es/kauron/jstudy/view/main.fxml +++ b/src/main/resources/es/kauron/jstudy/view/main.fxml @@ -21,7 +21,10 @@ - + + + + + + + + + + + + + + + + @@ -86,19 +98,6 @@ - - - - - - - - - - - - - diff --git a/src/main/resources/es/kauron/jstudy/view/table.fxml b/src/main/resources/es/kauron/jstudy/view/table.fxml index 2f2dc24..ef9ccd7 100644 --- a/src/main/resources/es/kauron/jstudy/view/table.fxml +++ b/src/main/resources/es/kauron/jstudy/view/table.fxml @@ -1,13 +1,12 @@ - - + @@ -18,7 +17,25 @@ - + - + + + +