diff --git a/src/main/java/at/ionas999/questioncatalog/controller/ViewController.java b/src/main/java/at/ionas999/questioncatalog/controller/ViewController.java index 0642441..6253c84 100644 --- a/src/main/java/at/ionas999/questioncatalog/controller/ViewController.java +++ b/src/main/java/at/ionas999/questioncatalog/controller/ViewController.java @@ -13,14 +13,18 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; +import javafx.collections.transformation.SortedList; import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.stage.Stage; import java.io.IOException; import java.sql.SQLException; +import java.util.Comparator; import static at.ionas999.questioncatalog.Utils.showConfirmationButton; @@ -30,7 +34,9 @@ public class ViewController { @FXML private ComboBox selectBox; @FXML - private Button editButton, deleteButton; + private ComboBox sortComboBox; + @FXML + private Button editButton, deleteButton, addButton; @FXML private TextField answerField, questionField; @FXML @@ -38,35 +44,92 @@ public class ViewController { private ObjectProperty currentQuestion = new SimpleObjectProperty<>(); private FilteredList questions; + private SortedList sortedQuestions; private final BooleanProperty isInEditState = new SimpleBooleanProperty(false); + private final BooleanProperty isInAddState = new SimpleBooleanProperty(false); + + private EventHandler originalEditAction; + private EventHandler originalDeleteAction; - @FXML + private enum SortOption { + CREATION_ORDER("Sort by Creation"), + QUESTION_ASC("Question (A-Z)"), + QUESTION_DESC("Question (Z-A)"); + + private final String displayName; + + SortOption(String displayName) { + this.displayName = displayName; + } + + @Override + public String toString() { + return displayName; + } + } + + @FXML private void initialize() throws SQLException { + //der Add btn ist mit ai erstellt worden (Claude 3.7) ObservableList catalogs = FXCollections.observableList(QuestionCatalogService.GetCatalogsWithoutQuestions()); selectBox.setItems(catalogs); selectBox.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> loadQuestions(newVal)); questionListView.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> updateCurrentQuestion(newVal)); - editButton.textProperty().bind(Bindings.when(isInEditState.not()).then("Edit").otherwise("Save")); - questionField.editableProperty().bind(isInEditState); - answerField.editableProperty().bind(isInEditState); - deleteButton.disableProperty().bind(isInEditState); - questionListView.disableProperty().bind(isInEditState); + sortComboBox.setItems(FXCollections.observableArrayList(SortOption.values())); + sortComboBox.getSelectionModel().select(SortOption.CREATION_ORDER); + sortComboBox.getSelectionModel().selectedItemProperty().addListener((_, _, newOption) -> { + if (sortedQuestions != null) { + applySorting(newOption); + } + }); + + BooleanProperty catalogSelected = new SimpleBooleanProperty(); + catalogSelected.bind(selectBox.getSelectionModel().selectedItemProperty().isNotNull()); + + sortComboBox.disableProperty().bind(selectBox.getSelectionModel().selectedItemProperty().isNull()); + + originalEditAction = editButton.getOnAction(); + originalDeleteAction = deleteButton.getOnAction(); + + editButton.textProperty().bind( + Bindings.when(isInAddState) + .then("Save New") + .otherwise(Bindings.when(isInEditState).then("Save").otherwise("Edit")) + ); + + questionField.editableProperty().bind(isInEditState.or(isInAddState).and(catalogSelected)); + answerField.editableProperty().bind(isInEditState.or(isInAddState).and(catalogSelected)); + + questionField.disableProperty().bind(catalogSelected.not()); + answerField.disableProperty().bind(catalogSelected.not()); + + // Update button and control disabling to handle add mode + deleteButton.disableProperty().bind( + isInEditState.or(catalogSelected.not()).or( + isInAddState.and( + questionField.textProperty().isEmpty().or(answerField.textProperty().isEmpty()) + ) + ) + ); + + addButton.disableProperty().bind(isInEditState.or(isInAddState).or(catalogSelected.not())); + + questionListView.disableProperty().bind(isInEditState.or(isInAddState).or(catalogSelected.not())); - // Disable searchField if no catalog is selected searchField.disableProperty().bind(selectBox.getSelectionModel().selectedItemProperty().isNull()); - // Disable editButton if fields are empty editButton.disableProperty().bind( questionField.textProperty().isEmpty() .or(answerField.textProperty().isEmpty()) .or(selectBox.getSelectionModel().selectedItemProperty().isNull()) ); - deleteButton.disableProperty().bind( + + deleteButton.disableProperty().bind( questionField.textProperty().isEmpty() .or(answerField.textProperty().isEmpty()) .or(selectBox.getSelectionModel().selectedItemProperty().isNull()) - ); + ); searchField.textProperty().addListener((_, _, newValue) -> { if (newValue == null) @@ -74,21 +137,50 @@ public class ViewController { String finalNewValue = newValue; questions.setPredicate(x -> x.getQuestion().toLowerCase().contains(finalNewValue.toLowerCase())); }); + + questionListView.setOnKeyPressed(this::handleKeyPress); + } + + private void handleKeyPress(KeyEvent event) { + if (event.getCode() == KeyCode.DELETE) { + if (currentQuestion.get() != null && !isInEditState.get()) { + deleteQuestion(); + } + } } private void loadQuestions(QuestionCatalog catalog) { if (catalog == null) return; try { questions = new FilteredList<>( - FXCollections.observableList - (QuestionService.GetQuestionsFromCatalog( - catalog.getId()))); - - questionListView.setItems(questions); + FXCollections.observableList( + QuestionService.GetQuestionsFromCatalog(catalog.getId()))); + + sortedQuestions = new SortedList<>(questions); + + applySorting(sortComboBox.getValue()); + + questionListView.setItems(sortedQuestions); } catch (SQLException e) { throw new RuntimeException(e); } } + + private void applySorting(SortOption sortOption) { + if (sortOption == null) return; + + switch (sortOption) { + case CREATION_ORDER: + sortedQuestions.setComparator(Comparator.comparingInt(Question::getId)); + break; + case QUESTION_ASC: + sortedQuestions.setComparator(Comparator.comparing(Question::getQuestion)); + break; + case QUESTION_DESC: + sortedQuestions.setComparator(Comparator.comparing(Question::getQuestion).reversed()); + break; + } + } private void updateCurrentQuestion(Question question) { if (question == null) return; @@ -119,9 +211,95 @@ public class ViewController { } } + @FXML + private void addQuestion() { + if (selectBox.getValue() == null) return; + + // Enter add mode + isInAddState.set(true); + + // Clear fields and selection + questionField.clear(); + answerField.clear(); + questionListView.getSelectionModel().clearSelection(); + currentQuestion.set(null); + + // Change delete button to cancel + deleteButton.setText("Cancel"); + + // Set temporary actions + deleteButton.setOnAction(e -> cancelAddQuestion()); + editButton.setOnAction(e -> saveNewQuestion()); + + // Focus the question field + questionField.requestFocus(); + } + + private void saveNewQuestion() { + String questionText = questionField.getText().trim(); + String answerText = answerField.getText().trim(); + + if (questionText.isEmpty() || answerText.isEmpty()) { + return; + } + + try { + // Use a temporary ID that will be ignored by AddQuestionToDb + int catalogId = selectBox.getValue().getId(); + Question newQuestion = new Question(0, questionText, answerText, catalogId); + + boolean success = QuestionService.AddQuestionToDb(newQuestion); + + if (success) { + // Refresh the questions list to include the new question + loadQuestions(selectBox.getValue()); + + // Exit add mode + resetAfterAdd(); + + // Show success message + showAlert(Alert.AlertType.INFORMATION, "Success", + "Question Added", "Question was added successfully."); + } else { + showAlert(Alert.AlertType.ERROR, "Error", + "Failed to add question", "Could not add question to the database."); + } + } catch (Exception e) { + showAlert(Alert.AlertType.ERROR, "Error", + "Error adding question", "An error occurred: " + e.getMessage()); + } + } + + private void cancelAddQuestion() { + resetAfterAdd(); + } + + private void resetAfterAdd() { + // Exit add mode + isInAddState.set(false); + + // Restore original button state + deleteButton.setText("Delete"); + deleteButton.setOnAction(originalDeleteAction); + editButton.setOnAction(originalEditAction); + + // Try to restore selection + if (!questionListView.getItems().isEmpty()) { + questionListView.getSelectionModel().selectFirst(); + } + } + + private void showAlert(Alert.AlertType type, String title, String header, String content) { + Alert alert = new Alert(type); + alert.setTitle(title); + alert.setHeaderText(header); + alert.setContentText(content); + alert.showAndWait(); + } + @FXML private void onBackToMainPageClick(ActionEvent actionEvent) throws IOException { Stage stage = Utils.getStageFromActionEven(actionEvent); Utils.switchScenes("main.fxml", stage); } -} \ No newline at end of file +} diff --git a/src/main/resources/at/ionas999/questioncatalog/view.fxml b/src/main/resources/at/ionas999/questioncatalog/view.fxml index c6a8a96..3faf027 100644 --- a/src/main/resources/at/ionas999/questioncatalog/view.fxml +++ b/src/main/resources/at/ionas999/questioncatalog/view.fxml @@ -45,8 +45,12 @@