implemented new design

This commit is contained in:
Jonas Hinterdorfer 2025-05-14 16:31:21 +02:00
parent fa666efaf8
commit 43c8792d70
2 changed files with 199 additions and 17 deletions

View File

@ -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<QuestionCatalog> selectBox;
@FXML
private Button editButton, deleteButton;
private ComboBox<SortOption> sortComboBox;
@FXML
private Button editButton, deleteButton, addButton;
@FXML
private TextField answerField, questionField;
@FXML
@ -38,30 +44,87 @@ public class ViewController {
private ObjectProperty<Question> currentQuestion = new SimpleObjectProperty<>();
private FilteredList<Question> questions;
private SortedList<Question> sortedQuestions;
private final BooleanProperty isInEditState = new SimpleBooleanProperty(false);
private final BooleanProperty isInAddState = new SimpleBooleanProperty(false);
private EventHandler<ActionEvent> originalEditAction;
private EventHandler<ActionEvent> originalDeleteAction;
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<QuestionCatalog> 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(
questionField.textProperty().isEmpty()
.or(answerField.textProperty().isEmpty())
@ -74,22 +137,51 @@ 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())));
FXCollections.observableList(
QuestionService.GetQuestionsFromCatalog(catalog.getId())));
questionListView.setItems(questions);
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;
currentQuestion.set(question);
@ -119,6 +211,92 @@ 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);

View File

@ -45,8 +45,12 @@
<Label text="Questions:" style="-fx-font-size: 14; -fx-font-weight: bold;"/>
<TextField fx:id="searchField" promptText="Search questions..."
style="-fx-background-color: white; -fx-border-color: #bdc3c7;"/>
<ComboBox fx:id="sortComboBox" promptText="Sort by..."
style="-fx-background-color: white; -fx-border-color: #bdc3c7; -fx-max-width: 1000;"/>
<ListView fx:id="questionListView" VBox.vgrow="ALWAYS"
style="-fx-background-color: white; -fx-border-color: #bdc3c7;"/>
<Button fx:id="addButton" text="Add Question" onAction="#addQuestion"
style="-fx-background-color: #27ae60; -fx-text-fill: white;"/>
</VBox>
</left>