Merge pull request #24 from RecentRunner/Pets

Pets CRUD
This commit is contained in:
2026-02-11 10:10:36 -07:00
committed by GitHub
5 changed files with 633 additions and 14 deletions

View File

@@ -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<Pet, Integer> colPetAge;
@FXML
private TableColumn<?, ?> colPetBreed;
private TableColumn<Pet, String> colPetBreed;
@FXML
private TableColumn<?, ?> colPetId;
private TableColumn<Pet, Integer> colPetId;
@FXML
private TableColumn<?, ?> colPetName;
private TableColumn<Pet, String> colPetName;
@FXML
private TableColumn<?, ?> colPetPrice;
private TableColumn<Pet, Double> colPetPrice;
@FXML
private TableColumn<?, ?> colPetSpecies;
private TableColumn<Pet, String> colPetSpecies;
@FXML
private TableColumn<?, ?> colPetStatus;
private TableColumn<Pet, String> colPetStatus;
@FXML
private TableView<?> tvPets;
private TableView<Pet> 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<ButtonType> 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<Pet> data = FXCollections.observableArrayList();
String mode = null;
@FXML
void initialize() {
btnEdit.setDisable(true);
btnDelete.setDisable(true);
colPetId.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petId"));
colPetName.setCellValueFactory(new PropertyValueFactory<Pet,String>("petName"));
colPetSpecies.setCellValueFactory(new PropertyValueFactory<Pet,String>("petSpecies"));
colPetBreed.setCellValueFactory(new PropertyValueFactory<Pet,String>("petBreed"));
colPetAge.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petAge"));
colPetStatus.setCellValueFactory(new PropertyValueFactory<Pet,String>("petStatus"));
colPetPrice.setCellValueFactory(new PropertyValueFactory<Pet,Double>("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("");
}
}

View File

@@ -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<String> 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<String> statusList = FXCollections.observableArrayList(
"Available", "Adopted"
);
@FXML
void initialize() {
cbPetStatus.setItems(statusList); //set status combobox
//Set up mouse handlers for buttons
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
buttonSaveClicked(mouseEvent);
}
});
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
@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);
}
}
}

View File

@@ -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<Pet> getPets() throws SQLException {
//Connect to the database
ObservableList<Pet> 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<Pet> getFilteredPets(String filter) throws SQLException {
//Connect to the database
ObservableList<Pet> 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;
}
}

View File

@@ -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;
}
}