From d42ea3462a8f2c806f6ec8edead03a728b925537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20K=C3=BCck?= Date: Fri, 17 May 2024 12:05:21 +0200 Subject: [PATCH] #18: WIP --- .../medication/AllMedicationController.java | 67 ++++++++-- .../nhplus/medication/IngredientListCell.java | 92 ++++++++++++++ .../medication/MedicationModalController.java | 118 ++++++++++++++++++ .../java/de/hitec/nhplus/utils/Validator.java | 24 ++++ .../nhplus/medication/AllMedicationView.fxml | 1 + 5 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 src/main/java/de/hitec/nhplus/medication/IngredientListCell.java create mode 100644 src/main/java/de/hitec/nhplus/medication/MedicationModalController.java diff --git a/src/main/java/de/hitec/nhplus/medication/AllMedicationController.java b/src/main/java/de/hitec/nhplus/medication/AllMedicationController.java index 5261958..2b4aab7 100644 --- a/src/main/java/de/hitec/nhplus/medication/AllMedicationController.java +++ b/src/main/java/de/hitec/nhplus/medication/AllMedicationController.java @@ -1,17 +1,24 @@ package de.hitec.nhplus.medication; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.stream.Collectors; + +import de.hitec.nhplus.Main; import de.hitec.nhplus.datastorage.DaoFactory; import de.hitec.nhplus.medication.database.MedicationDao; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; - -import java.sql.SQLException; -import java.util.stream.Collectors; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; /** * The controller for viewing all {@link Medication}s. @@ -50,14 +57,20 @@ public class AllMedicationController { this.columnName.setCellValueFactory(new PropertyValueFactory<>("name")); this.columnManufacturer.setCellValueFactory(new PropertyValueFactory<>("manufacturer")); this.columnIngredient.setCellValueFactory( - cellData -> new SimpleStringProperty( - cellData - .getValue() - .getIngredients() - .stream() - .map(ingredient -> ingredient.getName()) - .collect(Collectors.joining("\n")) - )); + cellData -> { + Medication medication = cellData.getValue(); + List ingredients = medication.getIngredients(); + if(ingredients.isEmpty()){ + return new SimpleStringProperty(""); + } + + return new SimpleStringProperty( + ingredients + .stream() + .map(ingredient -> ingredient.getName()) + .collect(Collectors.joining("\n")) + ); + }); this.columnPossibleSideEffects.setCellValueFactory(new PropertyValueFactory<>("possibleSideEffects")); this.columnAdministrationMethod.setCellValueFactory(new PropertyValueFactory<>("administrationMethod")); this.columnCurrentStock.setCellValueFactory(new PropertyValueFactory<>("currentStock")); @@ -76,4 +89,36 @@ public class AllMedicationController { exception.printStackTrace(); } } + + public void createMedication(Medication medication) { + dao = DaoFactory.getInstance().createMedicationDAO(); + try { + dao.create(medication); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } + + @FXML + public void handleNewMedication() { + try { + FXMLLoader loader = new FXMLLoader( + Main.class.getResource("/de/hitec/nhplus/medication/MedicationModal.fxml") + ); + BorderPane pane = loader.load(); + Scene scene = new Scene(pane); + Stage stage = new Stage(); + + MedicationModalController controller = loader.getController(); + controller.initialize(stage, this, null); + + stage.setScene(scene); + stage.setTitle("NHPlus - Neues Medikament"); + stage.setResizable(true); + stage.setAlwaysOnTop(true); + stage.showAndWait(); + } catch (IOException exception) { + exception.printStackTrace(); + } + } } diff --git a/src/main/java/de/hitec/nhplus/medication/IngredientListCell.java b/src/main/java/de/hitec/nhplus/medication/IngredientListCell.java new file mode 100644 index 0000000..0e15a32 --- /dev/null +++ b/src/main/java/de/hitec/nhplus/medication/IngredientListCell.java @@ -0,0 +1,92 @@ +package de.hitec.nhplus.medication; + +import javafx.beans.value.ObservableValue; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.text.Text; + +public class IngredientListCell extends ListCell { + private final TextField textField; + private final Button deleteButton; + + private static final double BUILTIN_BORDER_WIDTH = 1; + private static final double CELL_SPACING = 4; + private static final double CELL_PADDING = 4; + private static final double BUTTON_PADDING_X = 8; + private static final double BUTTON_PADDING_Y = 4; + private final double totalSpacing; + + public IngredientListCell() { + this.setPadding(new Insets(CELL_PADDING)); + + textField = new TextField(); + textField.setPromptText("Inhaltsstoff"); + textField.textProperty().addListener(this::onTextFieldUpdate); + + deleteButton = new Button("-"); + deleteButton.setPadding(new Insets( + BUTTON_PADDING_Y, + BUTTON_PADDING_X, + BUTTON_PADDING_Y, + BUTTON_PADDING_X + )); + deleteButton.setOnAction(event -> getListView().getItems().remove(this)); + + // Calculate Delete Button Width + Text textNode = new Text(deleteButton.getText()); + textNode.setFont(deleteButton.getFont()); + double calculatedDeleteButtonWidth = textNode.getLayoutBounds().getWidth() + BUTTON_PADDING_X * 2; + + totalSpacing = BUILTIN_BORDER_WIDTH * 2 // List View + + CELL_PADDING * 2 + + CELL_SPACING + + calculatedDeleteButtonWidth; + } + + @Override + protected void updateItem(Ingredient item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setGraphic(null); + } else { + String oldText = textField.getText(); + String newText = oldText != null && !oldText.isEmpty() ? oldText : item.getName(); + textField.setText(newText); + + BorderPane cellPane = new BorderPane(); + cellPane.setCenter(textField); + cellPane.setRight(deleteButton); + BorderPane.setMargin(deleteButton, new Insets(0, 0, 0, CELL_SPACING)); + setGraphic(cellPane); + } + } + + private void onTextFieldUpdate(ObservableValue observable, String oldValue, String newValue) { + getItem().setName(textField.getText()); + + textField.setMinWidth(getTextFieldRequiredWidth(textField)); + + ListView listView = getListView(); + double max = listView.lookupAll("*") + .stream() + .filter(node -> node instanceof IngredientListCell) + .mapToDouble(node -> getTextFieldRequiredWidth(((IngredientListCell) node).textField)) + .max() + .orElse(0); + + getListView().setMinWidth(max + totalSpacing); + } + + private double getTextFieldRequiredWidth(TextField textField) { + Text textNode = new Text(textField.getText()); + textNode.setFont(textField.getFont()); + return textNode.getLayoutBounds().getWidth() + + textField.getPadding().getLeft() + + textField.getPadding().getRight() + + BUILTIN_BORDER_WIDTH * 2; + } +} diff --git a/src/main/java/de/hitec/nhplus/medication/MedicationModalController.java b/src/main/java/de/hitec/nhplus/medication/MedicationModalController.java new file mode 100644 index 0000000..c8f572f --- /dev/null +++ b/src/main/java/de/hitec/nhplus/medication/MedicationModalController.java @@ -0,0 +1,118 @@ +package de.hitec.nhplus.medication; + +import javafx.beans.value.ChangeListener; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ListView; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.stage.Stage; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import static de.hitec.nhplus.utils.Validator.*; + +public class MedicationModalController { + + @FXML + public ListView listViewIngredients; + @FXML + public TextField textFieldName; + @FXML + public TextField textFieldManufacturer; + @FXML + public TextField textFieldAdministrationMethod; + @FXML + public TextField textFieldCurrentStock; + @FXML + public TextArea textAreaPossibleSideEffects; + @FXML + public Button buttonSave; + + private Stage stage; + private Medication medication; + private final ObservableList ingredients = FXCollections.observableArrayList(); + private AllMedicationController controller; + + @FXML + public void initialize(Stage stage, AllMedicationController controller, Medication medication) { + this.stage = stage; + this.controller=controller; + + if( medication != null){ + this.medication = medication; + }else { + this.medication = new Medication( + "", + "", + new ArrayList<>(), + "", + "", + 0 + ); + this.buttonSave.setDisable(true); + } + + listViewIngredients.setCellFactory(cellData -> new IngredientListCell()); + listViewIngredients.setItems(ingredients); + showData(); + + ChangeListener inputMedicationValidationListener = (observableValue, oldText, newText) -> { + boolean isValid = isValidMedicationName(textFieldName.getText()) + && isValidMedicationManufacturer(textFieldManufacturer.getText()) + && isValidMedicationAdministrationMethod(textFieldAdministrationMethod.getText()) + && isValidStock(textFieldCurrentStock.getText()); + + this.buttonSave.setDisable(!isValid); + }; + + this.textFieldName.textProperty().addListener(inputMedicationValidationListener); + this.textFieldManufacturer.textProperty().addListener(inputMedicationValidationListener); + this.textFieldAdministrationMethod.textProperty().addListener(inputMedicationValidationListener); + this.textFieldCurrentStock.textProperty().addListener(inputMedicationValidationListener); + } + + private void showData(){ + ingredients.setAll(medication.getIngredients()); + textFieldName.setText(medication.getName()); + textFieldManufacturer.setText(medication.getManufacturer()); + textFieldAdministrationMethod.setText(medication.getAdministrationMethod()); + textFieldCurrentStock.setText(String.valueOf(medication.getCurrentStock())); + textAreaPossibleSideEffects.setText(medication.getPossibleSideEffects()); + } + + @FXML + public void handleSave() { + this.medication.setName(textFieldName.getText()); + this.medication.setManufacturer(textFieldManufacturer.getText()); + this.medication.setAdministrationMethod(textFieldAdministrationMethod.getText()); + this.medication.setCurrentStock(Integer.parseInt(textFieldCurrentStock.getText())); + this.medication.setPossibleSideEffects(textAreaPossibleSideEffects.getText()); + this.medication.setIngredients(ingredients + .stream() + .map(Ingredient::getName) + .distinct() + .filter(Predicate.not(String::isEmpty)) + .map(Ingredient::new) + .toList() + ); + + controller.createMedication(medication); + controller.readAllAndShowInTableView(); + stage.close(); + } + + @FXML + public void handleCancel() { + stage.close(); + } + + @FXML + public void handleAddIngredient() { + ingredients.add(new Ingredient("")); + } +} diff --git a/src/main/java/de/hitec/nhplus/utils/Validator.java b/src/main/java/de/hitec/nhplus/utils/Validator.java index 7931700..f331fa9 100644 --- a/src/main/java/de/hitec/nhplus/utils/Validator.java +++ b/src/main/java/de/hitec/nhplus/utils/Validator.java @@ -148,4 +148,28 @@ public class Validator { public static boolean isValidRoomNumber(String text) { return !text.isBlank(); } + + public static boolean isValidMedicationName(String text) { + return !text.isBlank(); + } + + public static boolean isValidMedicationManufacturer(String text) { + return !text.isBlank(); + } + + public static boolean isValidMedicationAdministrationMethod(String text) { + return !text.isBlank(); + } + + public static boolean isValidStock(String text) { + if (text.isBlank()) { + return false; + } + try { + int stock = Integer.parseInt(text); + return stock >= 0; + } catch (Exception exception) { + return false; + } + } } diff --git a/src/main/resources/de/hitec/nhplus/medication/AllMedicationView.fxml b/src/main/resources/de/hitec/nhplus/medication/AllMedicationView.fxml index f5ee43b..53e03b9 100644 --- a/src/main/resources/de/hitec/nhplus/medication/AllMedicationView.fxml +++ b/src/main/resources/de/hitec/nhplus/medication/AllMedicationView.fxml @@ -66,6 +66,7 @@ fx:id="buttonAdd" mnemonicParsing="false" prefWidth="90.0" + onAction="#handleNewMedication" text="Hinzufügen" />