diff --git a/connectionpetstore.properties b/connectionpetstore.properties new file mode 100644 index 00000000..426ecafb --- /dev/null +++ b/connectionpetstore.properties @@ -0,0 +1,3 @@ +url=jdbc:mysql://127.0.0.1:3306/Petstoredb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC +user=petapp +password=petapppass \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/PetController.java b/src/main/java/org/example/petshopdesktop/controllers/PetController.java index 26834d72..7eb55cb8 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PetController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PetController.java @@ -1,11 +1,24 @@ package org.example.petshopdesktop.controllers; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.control.TextField; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.stage.Modality; +import javafx.stage.Stage; +import org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogController; +import org.example.petshopdesktop.database.PetDB; +import org.example.petshopdesktop.database.ProductDB; +import org.example.petshopdesktop.models.Pet; + +import java.io.IOException; +import java.sql.SQLException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.Optional; public class PetController { @@ -19,45 +32,191 @@ public class PetController { private Button btnEdit; @FXML - private TableColumn colPetAge; + private TableColumn colPetAge; @FXML - private TableColumn colPetBreed; + private TableColumn colPetBreed; @FXML - private TableColumn colPetId; + private TableColumn colPetId; @FXML - private TableColumn colPetName; + private TableColumn colPetName; @FXML - private TableColumn colPetPrice; + private TableColumn colPetPrice; @FXML - private TableColumn colPetSpecies; + private TableColumn colPetSpecies; @FXML - private TableColumn colPetStatus; + private TableColumn colPetStatus; @FXML - private TableView tvPets; + private TableView tvPets; @FXML private TextField txtSearch; @FXML void btnAddClicked(ActionEvent event) { - + mode = "Add"; + openDialog(null,mode); } @FXML void btnDeleteClicked(ActionEvent event) { + int numRows = 0; + Pet selectedPet = tvPets.getSelectionModel().getSelectedItem(); + //ask user to confirm + Alert question = new Alert(Alert.AlertType.CONFIRMATION); + question.setHeaderText("Please confirm delete"); + question.setContentText("Are you sure you want to delete this pet?"); + Optional result = question.showAndWait(); //show alert and wait for response + + //if confirmed,start deletion + if (result.isPresent() && result.get() == ButtonType.OK) { + int petId = selectedPet.getPetId(); + + //try deleting + try{ + numRows = PetDB.deletePet(petId); + } + catch (SQLIntegrityConstraintViolationException e){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Delete failed\n" + + "the selected pet is being referred in another table"); + alert.showAndWait(); + return; + } + catch (SQLException e) { + throw new RuntimeException(e); + } + + //prompt user of any errors + if (numRows == 0){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Delete failed"); + alert.showAndWait(); + } + else{ + //prompt user of delete conformation + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText("Delete successful"); + alert.showAndWait(); + //refresh display and reset inputs + displayPets(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); + } + } } @FXML void btnEditClicked(ActionEvent event) { + Pet selectedPet = tvPets.getSelectionModel().getSelectedItem(); + if(selectedPet != null){ + mode = "Edit"; + openDialog(selectedPet,mode); + } } -} + private ObservableList data = FXCollections.observableArrayList(); + String mode = null; + + @FXML + void initialize() { + btnEdit.setDisable(true); + btnDelete.setDisable(true); + + colPetId.setCellValueFactory(new PropertyValueFactory("petId")); + colPetName.setCellValueFactory(new PropertyValueFactory("petName")); + colPetSpecies.setCellValueFactory(new PropertyValueFactory("petSpecies")); + colPetBreed.setCellValueFactory(new PropertyValueFactory("petBreed")); + colPetAge.setCellValueFactory(new PropertyValueFactory("petAge")); + colPetStatus.setCellValueFactory(new PropertyValueFactory("petStatus")); + colPetPrice.setCellValueFactory(new PropertyValueFactory("petPrice")); + + displayPets(); + + tvPets.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> { + btnEdit.setDisable(false); + btnDelete.setDisable(false); + }); + + txtSearch.textProperty().addListener((observable, oldValue, newValue) -> { + displayFilteredPet(newValue); + }); + } + + private void displayFilteredPet(String filter) { + data.clear(); + try{ + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displayPets(); + } + else { + data = PetDB.getFilteredPets(filter); + tvPets.setItems(data); + } + } catch (Exception e) { + System.out.println("Error while fetching table data: " + e.getMessage()); + } + } + + private void displayPets() { + data.clear(); + + try{ + data = PetDB.getPets(); + } + catch(SQLException e){ + System.out.println("Error while fetching table data: " + e.getMessage()); + } + + tvPets.setItems(data); + } + + private void openDialog(Pet pet, String mode){ + //Get new view + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml")); + Scene scene = null; + try{ + scene = new Scene(fxmlLoader.load()); + } catch (IOException e) { + throw new RuntimeException(e); + } + PetDialogController dialogController = fxmlLoader.getController(); //controller associated with this view + dialogController.setMode(mode); + + //Open the dialog depending on the mode + if(mode.equals("Edit")){ + //Make it display pet details in dialog + dialogController.displayPetDetails(pet); + } + Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal + if(mode.equals("Add")){ + dialogStage.setTitle("Add Pet"); + } + else { + dialogStage.setTitle("Edit Pet"); + } + dialogStage.setScene(scene); + dialogStage.showAndWait(); + + //When dialog closes update table view and disable edit and delete buttons, and reset search bar + displayPets(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); + } + +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java new file mode 100644 index 00000000..45be6c3c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java @@ -0,0 +1,203 @@ +package org.example.petshopdesktop.controllers.dialogcontrollers; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; +import org.example.petshopdesktop.DTOs.ProductDTO; +import org.example.petshopdesktop.Validator; +import org.example.petshopdesktop.database.PetDB; +import org.example.petshopdesktop.models.Category; +import org.example.petshopdesktop.models.Pet; + +import java.sql.SQLException; + +public class PetDialogController { + + @FXML + private Button btnCancel; + + @FXML + private Button btnSave; + + @FXML + private ComboBox cbPetStatus; + + @FXML + private Label lblMode; + + @FXML + private Label lblPetId; + + @FXML + private TextField txtPetAge; + + @FXML + private TextField txtPetBreed; + + @FXML + private TextField txtPetName; + + @FXML + private TextField txtPetPrice; + + @FXML + private TextField txtPetSpecies; + + private String mode = null; + + private ObservableList statusList = FXCollections.observableArrayList( + "Available", "Adopted" + ); + + @FXML + void initialize() { + + cbPetStatus.setItems(statusList); //set status combobox + + //Set up mouse handlers for buttons + btnSave.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent mouseEvent) { + buttonSaveClicked(mouseEvent); + } + }); + + btnCancel.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent mouseEvent) { + closeStage(mouseEvent); + } + }); + } + + private void buttonSaveClicked(MouseEvent mouseEvent) { + int numRow = 0; + String errorMsg = ""; + + //Check validation (input required) + errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name"); + errorMsg += Validator.isPresent(txtPetAge.getText(), "Age"); + errorMsg += Validator.isPresent(txtPetBreed.getText(), "Breed"); + errorMsg += Validator.isPresent(txtPetSpecies.getText(), "Species"); + errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price"); + if (cbPetStatus.getSelectionModel().getSelectedItem() == null){ + errorMsg += "Status is required"; + } + + //Check validation (length size) + errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50); + errorMsg += Validator.isLessThanVarChars(txtPetSpecies.getText(), "Species", 50); + errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50); + errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12); + errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11); + + //Check validation (format) + errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price"); + errorMsg += Validator.isNonNegativeInteger(txtPetAge.getText(), "Age"); + + if(errorMsg.isEmpty()){ + Pet pet = collectPet(); + if(mode.equals("Add")) { + try{ + numRow = PetDB.insertPet(pet); + } + catch (SQLException e) { + throw new RuntimeException(e); + } + } + else { + try { + numRow = PetDB.updatePet(pet.getPetId(), pet); + } + catch (SQLException e) { + throw new RuntimeException(e); + } + } + + //if no rows were affected then there was an error (prompt user of error) + if (numRow == 0){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(mode + " failed"); + alert.showAndWait(); + closeStage(mouseEvent); + } + else { + //tell the user operation was successful + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText(mode + " succeeded"); + alert.showAndWait(); + closeStage(mouseEvent); + } + } + else{ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Input Error"); + alert.setContentText(errorMsg); + alert.showAndWait(); + } + } + + private Pet collectPet() { + int petId =0; + Pet pet = null; + + if(lblPetId.isVisible()){ + petId = Integer.parseInt(lblPetId.getText().split(": ")[1]); + } + pet = new Pet( + petId, + txtPetName.getText(), + txtPetSpecies.getText(), + txtPetBreed.getText(), + Integer.parseInt(txtPetAge.getText()), + cbPetStatus.getValue(), + Double.parseDouble(txtPetPrice.getText()) + ); + return pet; + } + + private void closeStage(MouseEvent mouseEvent) { + Node node = (Node) mouseEvent.getSource(); + Stage stage = (Stage) node.getScene().getWindow(); + stage.close(); + } + + public void displayPetDetails(Pet pet){ + if (pet!=null){ + lblPetId.setText("ID: " + pet.getPetId()); + txtPetName.setText(pet.getPetName()); + txtPetSpecies.setText(pet.getPetSpecies()); + txtPetBreed.setText(pet.getPetBreed()); + txtPetAge.setText(pet.getPetAge() + ""); + txtPetPrice.setText(pet.getPetPrice() + ""); + + //get the right combobox selection + for (String status : cbPetStatus.getItems()) { + if(status.equals(pet.getPetStatus())){ + cbPetStatus.getSelectionModel().select(status); + } + } + + + } + } + + public void setMode(String mode) { + this.mode = mode; + lblMode.setText(mode + " Pet"); + if(mode.equals("Add")) { + lblPetId.setVisible(false); + } + else if(mode.equals("Edit")) { + lblPetId.setVisible(true); + } + } + +} diff --git a/src/main/java/org/example/petshopdesktop/database/PetDB.java b/src/main/java/org/example/petshopdesktop/database/PetDB.java new file mode 100644 index 00000000..d1b7ca37 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/PetDB.java @@ -0,0 +1,145 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.example.petshopdesktop.models.Pet; + +import java.sql.*; + +public class PetDB { + public static ObservableList getPets() throws SQLException { + //Connect to the database + ObservableList pets = FXCollections.observableArrayList(); + Connection conn = ConnectionDB.getConnection(); + + //Execute Query + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM pet"); + + //While there is still data add pets to the list + while(rs.next()){ + Pet pet = new Pet( + rs.getInt(1), + rs.getString(2), + rs.getString(3), + rs.getString(4), + rs.getInt(5), + rs.getString(6), + rs.getDouble(7) + ); + pets.add(pet); + } + + //close connection and return pets + conn.close(); + return pets; + } + + public static ObservableList getFilteredPets(String filter) throws SQLException { + //Connect to the database + ObservableList pets = FXCollections.observableArrayList(); + Connection conn = ConnectionDB.getConnection(); + + //Get SQL query for filtered word + String sql = "SELECT * FROM pet " + + " WHERE " + + "petName LIKE ? OR " + + "petSpecies LIKE ? OR " + + "petBreed LIKE ? OR " + + "petAge LIKE ? OR " + + "petStatus LIKE ? OR " + + "petPrice LIKE ?"; + + String filteredString = "%" + filter + "%"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setString(1, filteredString); + stmt.setString(2, filteredString); + stmt.setString(3, filteredString); + stmt.setString(4, filteredString); + stmt.setString(5, filteredString); + stmt.setString(6, filteredString); + + ResultSet rs = stmt.executeQuery(); + + while(rs.next()){ + Pet pet = new Pet( + rs.getInt(1), + rs.getString(2), + rs.getString(3), + rs.getString(4), + rs.getInt(5), + rs.getString(6), + rs.getDouble(7) + ); + pets.add(pet); + } + + conn.close(); + return pets; + } + + public static int insertPet(Pet pet) throws SQLException { + int numRows = 0; + + Connection conn = ConnectionDB.getConnection(); + String sql = "INSERT INTO pet (petId, petName, petSpecies, petBreed, petAge, petStatus, petPrice)" + + " VALUES (?, ?, ?, ?, ?, ?, ?)"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, pet.getPetId()); + stmt.setString(2, pet.getPetName()); + stmt.setString(3, pet.getPetSpecies()); + stmt.setString(4, pet.getPetBreed()); + stmt.setInt(5, pet.getPetAge()); + stmt.setString(6, pet.getPetStatus()); + stmt.setDouble(7, pet.getPetPrice()); + + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } + + public static int updatePet(int petId, Pet pet) throws SQLException { + int numRows = 0; + + Connection conn = ConnectionDB.getConnection(); + String sql = "UPDATE pet SET " + + " petName = ?, " + + " petSpecies = ?, " + + " petBreed = ?, " + + " petAge = ?, " + + " petStatus = ?, " + + " petPrice = ? " + + " WHERE petId = ?"; + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setString(1, pet.getPetName()); + stmt.setString(2, pet.getPetSpecies()); + stmt.setString(3, pet.getPetBreed()); + stmt.setInt(4, pet.getPetAge()); + stmt.setString(5, pet.getPetStatus()); + stmt.setDouble(6, pet.getPetPrice()); + stmt.setInt(7, petId); + + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } + + public static int deletePet(int petId) throws SQLException { + int numRows = 0; + Connection conn = ConnectionDB.getConnection(); + + String sql = "DELETE FROM pet WHERE petId = ?"; + PreparedStatement stmt = conn.prepareStatement(sql); + + stmt.setInt(1, petId); + + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } +} diff --git a/src/main/java/org/example/petshopdesktop/models/Pet.java b/src/main/java/org/example/petshopdesktop/models/Pet.java new file mode 100644 index 00000000..e1f2e3fb --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/Pet.java @@ -0,0 +1,109 @@ +package org.example.petshopdesktop.models; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +public class Pet { + private SimpleIntegerProperty petId; + private SimpleStringProperty petName; + private SimpleStringProperty petSpecies; + private SimpleStringProperty petBreed; + private SimpleIntegerProperty petAge; + private SimpleStringProperty petStatus; + private SimpleDoubleProperty petPrice; + + public Pet(int petId, String petName, String petSpecies, String petBreed, int petAge, String petStatus, double petPrice) { + this.petId = new SimpleIntegerProperty(petId); + this.petName = new SimpleStringProperty(petName); + this.petSpecies = new SimpleStringProperty(petSpecies); + this.petBreed = new SimpleStringProperty(petBreed); + this.petAge = new SimpleIntegerProperty(petAge); + this.petStatus = new SimpleStringProperty(petStatus); + this.petPrice = new SimpleDoubleProperty(petPrice); + } + + public int getPetId() { + return petId.get(); + } + + public void setPetId(int petId) { + this.petId.set(petId); + } + + public SimpleIntegerProperty petIdProperty() { + return petId; + } + + public String getPetName() { + return petName.get(); + } + + public void setPetName(String petName) { + this.petName.set(petName); + } + + public SimpleStringProperty petNameProperty() { + return petName; + } + + public String getPetSpecies() { + return petSpecies.get(); + } + + public void setPetSpecies(String petSpecies) { + this.petSpecies.set(petSpecies); + } + + public SimpleStringProperty petSpeciesProperty() { + return petSpecies; + } + + public String getPetBreed() { + return petBreed.get(); + } + + public void setPetBreed(String petBreed) { + this.petBreed.set(petBreed); + } + + public SimpleStringProperty petBreedProperty() { + return petBreed; + } + + public int getPetAge() { + return petAge.get(); + } + + public void setPetAge(int petAge) { + this.petAge.set(petAge); + } + + public SimpleIntegerProperty petAgeProperty() { + return petAge; + } + + public String getPetStatus() { + return petStatus.get(); + } + + public void setPetStatus(String petStatus) { + this.petStatus.set(petStatus); + } + + public SimpleStringProperty petStatusProperty() { + return petStatus; + } + + public double getPetPrice() { + return petPrice.get(); + } + + public void setPetPrice(double petPrice) { + this.petPrice.set(petPrice); + } + + public SimpleDoubleProperty petPriceProperty() { + return petPrice; + } +}