implemented new design
This commit is contained in:
parent
fa666efaf8
commit
43c8792d70
@ -13,14 +13,18 @@ import javafx.beans.property.SimpleObjectProperty;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.FilteredList;
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.collections.transformation.SortedList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
import static at.ionas999.questioncatalog.Utils.showConfirmationButton;
|
import static at.ionas999.questioncatalog.Utils.showConfirmationButton;
|
||||||
|
|
||||||
@ -30,7 +34,9 @@ public class ViewController {
|
|||||||
@FXML
|
@FXML
|
||||||
private ComboBox<QuestionCatalog> selectBox;
|
private ComboBox<QuestionCatalog> selectBox;
|
||||||
@FXML
|
@FXML
|
||||||
private Button editButton, deleteButton;
|
private ComboBox<SortOption> sortComboBox;
|
||||||
|
@FXML
|
||||||
|
private Button editButton, deleteButton, addButton;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField answerField, questionField;
|
private TextField answerField, questionField;
|
||||||
@FXML
|
@FXML
|
||||||
@ -38,35 +44,92 @@ public class ViewController {
|
|||||||
|
|
||||||
private ObjectProperty<Question> currentQuestion = new SimpleObjectProperty<>();
|
private ObjectProperty<Question> currentQuestion = new SimpleObjectProperty<>();
|
||||||
private FilteredList<Question> questions;
|
private FilteredList<Question> questions;
|
||||||
|
private SortedList<Question> sortedQuestions;
|
||||||
private final BooleanProperty isInEditState = new SimpleBooleanProperty(false);
|
private final BooleanProperty isInEditState = new SimpleBooleanProperty(false);
|
||||||
|
private final BooleanProperty isInAddState = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
|
private EventHandler<ActionEvent> originalEditAction;
|
||||||
|
private EventHandler<ActionEvent> 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 {
|
private void initialize() throws SQLException {
|
||||||
|
//der Add btn ist mit ai erstellt worden (Claude 3.7)
|
||||||
ObservableList<QuestionCatalog> catalogs = FXCollections.observableList(QuestionCatalogService.GetCatalogsWithoutQuestions());
|
ObservableList<QuestionCatalog> catalogs = FXCollections.observableList(QuestionCatalogService.GetCatalogsWithoutQuestions());
|
||||||
selectBox.setItems(catalogs);
|
selectBox.setItems(catalogs);
|
||||||
selectBox.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> loadQuestions(newVal));
|
selectBox.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> loadQuestions(newVal));
|
||||||
questionListView.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> updateCurrentQuestion(newVal));
|
questionListView.getSelectionModel().selectedItemProperty().addListener((_, _, newVal) -> updateCurrentQuestion(newVal));
|
||||||
|
|
||||||
editButton.textProperty().bind(Bindings.when(isInEditState.not()).then("Edit").otherwise("Save"));
|
sortComboBox.setItems(FXCollections.observableArrayList(SortOption.values()));
|
||||||
questionField.editableProperty().bind(isInEditState);
|
sortComboBox.getSelectionModel().select(SortOption.CREATION_ORDER);
|
||||||
answerField.editableProperty().bind(isInEditState);
|
sortComboBox.getSelectionModel().selectedItemProperty().addListener((_, _, newOption) -> {
|
||||||
deleteButton.disableProperty().bind(isInEditState);
|
if (sortedQuestions != null) {
|
||||||
questionListView.disableProperty().bind(isInEditState);
|
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());
|
searchField.disableProperty().bind(selectBox.getSelectionModel().selectedItemProperty().isNull());
|
||||||
|
|
||||||
// Disable editButton if fields are empty
|
|
||||||
editButton.disableProperty().bind(
|
editButton.disableProperty().bind(
|
||||||
questionField.textProperty().isEmpty()
|
questionField.textProperty().isEmpty()
|
||||||
.or(answerField.textProperty().isEmpty())
|
.or(answerField.textProperty().isEmpty())
|
||||||
.or(selectBox.getSelectionModel().selectedItemProperty().isNull())
|
.or(selectBox.getSelectionModel().selectedItemProperty().isNull())
|
||||||
);
|
);
|
||||||
deleteButton.disableProperty().bind(
|
|
||||||
|
deleteButton.disableProperty().bind(
|
||||||
questionField.textProperty().isEmpty()
|
questionField.textProperty().isEmpty()
|
||||||
.or(answerField.textProperty().isEmpty())
|
.or(answerField.textProperty().isEmpty())
|
||||||
.or(selectBox.getSelectionModel().selectedItemProperty().isNull())
|
.or(selectBox.getSelectionModel().selectedItemProperty().isNull())
|
||||||
);
|
);
|
||||||
|
|
||||||
searchField.textProperty().addListener((_, _, newValue) -> {
|
searchField.textProperty().addListener((_, _, newValue) -> {
|
||||||
if (newValue == null)
|
if (newValue == null)
|
||||||
@ -74,21 +137,50 @@ public class ViewController {
|
|||||||
String finalNewValue = newValue;
|
String finalNewValue = newValue;
|
||||||
questions.setPredicate(x -> x.getQuestion().toLowerCase().contains(finalNewValue.toLowerCase()));
|
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) {
|
private void loadQuestions(QuestionCatalog catalog) {
|
||||||
if (catalog == null) return;
|
if (catalog == null) return;
|
||||||
try {
|
try {
|
||||||
questions = new FilteredList<>(
|
questions = new FilteredList<>(
|
||||||
FXCollections.observableList
|
FXCollections.observableList(
|
||||||
(QuestionService.GetQuestionsFromCatalog(
|
QuestionService.GetQuestionsFromCatalog(catalog.getId())));
|
||||||
catalog.getId())));
|
|
||||||
|
sortedQuestions = new SortedList<>(questions);
|
||||||
questionListView.setItems(questions);
|
|
||||||
|
applySorting(sortComboBox.getValue());
|
||||||
|
|
||||||
|
questionListView.setItems(sortedQuestions);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(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) {
|
private void updateCurrentQuestion(Question question) {
|
||||||
if (question == null) return;
|
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
|
@FXML
|
||||||
private void onBackToMainPageClick(ActionEvent actionEvent) throws IOException {
|
private void onBackToMainPageClick(ActionEvent actionEvent) throws IOException {
|
||||||
Stage stage = Utils.getStageFromActionEven(actionEvent);
|
Stage stage = Utils.getStageFromActionEven(actionEvent);
|
||||||
Utils.switchScenes("main.fxml", stage);
|
Utils.switchScenes("main.fxml", stage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,8 +45,12 @@
|
|||||||
<Label text="Questions:" style="-fx-font-size: 14; -fx-font-weight: bold;"/>
|
<Label text="Questions:" style="-fx-font-size: 14; -fx-font-weight: bold;"/>
|
||||||
<TextField fx:id="searchField" promptText="Search questions..."
|
<TextField fx:id="searchField" promptText="Search questions..."
|
||||||
style="-fx-background-color: white; -fx-border-color: #bdc3c7;"/>
|
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"
|
<ListView fx:id="questionListView" VBox.vgrow="ALWAYS"
|
||||||
style="-fx-background-color: white; -fx-border-color: #bdc3c7;"/>
|
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>
|
</VBox>
|
||||||
</left>
|
</left>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user