From 96b50a21beaad11c7030d7e8162d32dd283dce94 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Wed, 25 Feb 2026 10:08:47 -0700 Subject: [PATCH] Add multi-row selection and deletion to all tables --- .../controllers/AdoptionController.java | 87 +++++++++------ .../controllers/AppointmentController.java | 59 ++++++++-- .../controllers/InventoryController.java | 98 ++++++++-------- .../controllers/PetController.java | 97 +++++++++------- .../controllers/ProductController.java | 100 +++++++++-------- .../ProductSupplierController.java | 105 ++++++++++-------- .../controllers/ServiceController.java | 59 ++++++++-- .../controllers/SupplierController.java | 100 +++++++++-------- 8 files changed, 427 insertions(+), 278 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java index 5cd29fa5..c60ddf83 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java @@ -62,6 +62,8 @@ public class AdoptionController { void initialize() { btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvAdoptions.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId")); colPetId.setCellValueFactory(new PropertyValueFactory<>("petId")); @@ -100,54 +102,71 @@ public class AdoptionController { @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - Adoption selectedAdoption = tvAdoptions.getSelectionModel().getSelectedItem(); + //get selected adoptions + var selectedAdoptions = tvAdoptions.getSelectionModel().getSelectedItems(); + if (selectedAdoptions.isEmpty()) return; + //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 adoption record?"); + String message = selectedAdoptions.size() == 1 + ? "Are you sure you want to delete this adoption record?" + : "Are you sure you want to delete " + selectedAdoptions.size() + " adoption records?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); Optional result = question.showAndWait(); + //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int adoptionId = selectedAdoption.getAdoptionId(); + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - try { - numRows = AdoptionDB.deleteAdoption(adoptionId); - } - catch (SQLIntegrityConstraintViolationException e) { - ActivityLogger.getInstance().logException( - "AdoptionController.btnDeleteClicked", - e, - "Deleting adoption (integrity constraint violation) with ID: " + adoptionId); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed\nThe selected adoption is being referred in another table"); - alert.showAndWait(); - return; - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionController.btnDeleteClicked", - e, - "Deleting adoption with ID: " + adoptionId); - throw new RuntimeException(e); + for (Adoption adoption : selectedAdoptions) { + try { + int numRows = AdoptionDB.deleteAdoption(adoption.getAdoptionId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e) { + ActivityLogger.getInstance().logException( + "AdoptionController.btnDeleteClicked", + e, + String.format("Attempting to delete adoption ID %d - foreign key constraint", adoption.getAdoptionId())); + failCount++; + errors.append("Adoption ID ").append(adoption.getAdoptionId()).append(" is referenced in another table\n"); + } catch (SQLException e) { + ActivityLogger.getInstance().logException( + "AdoptionController.btnDeleteClicked", + e, + String.format("Attempting to delete adoption ID %d", adoption.getAdoptionId())); + failCount++; + errors.append("Failed to delete adoption ID ").append(adoption.getAdoptionId()).append("\n"); + } } - if (numRows == 0) { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - } else { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " adoption record(s)"); alert.showAndWait(); - displayAdoptions(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displayAdoptions(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java index 54e168b6..ac1a2c35 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java @@ -40,6 +40,8 @@ public class AppointmentController { @FXML public void initialize(){ + //Enable multiple selection + tvAppointments.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colAppointmentId.setCellValueFactory(new PropertyValueFactory<>("appointmentId")); colPetName.setCellValueFactory(new PropertyValueFactory<>("petName")); @@ -127,21 +129,56 @@ public class AppointmentController { @FXML void btnDeleteClicked(ActionEvent event){ + //get selected appointments + var selectedAppointments = tvAppointments.getSelectionModel().getSelectedItems(); + if (selectedAppointments.isEmpty()) return; - AppointmentDTO selected = - tvAppointments.getSelectionModel().getSelectedItem(); + //ask user to confirm + Alert question = new Alert(Alert.AlertType.CONFIRMATION); + question.setHeaderText("Please confirm delete"); + String message = selectedAppointments.size() == 1 + ? "Are you sure you want to delete this appointment?" + : "Are you sure you want to delete " + selectedAppointments.size() + " appointments?"; + question.setContentText(message); + question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); + java.util.Optional result = question.showAndWait(); - if(selected == null) return; + //if confirmed, start deletion + if (result.isPresent() && result.get() == ButtonType.OK) { + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - try{ - AppointmentDB.deleteAppointment(selected.getAppointmentId()); + for (AppointmentDTO appointment : selectedAppointments) { + try{ + AppointmentDB.deleteAppointment(appointment.getAppointmentId()); + successCount++; + }catch(Exception e){ + ActivityLogger.getInstance().logException( + "AppointmentController.btnDeleteClicked", + e, + String.format("Attempting to delete appointment ID %d", appointment.getAppointmentId())); + failCount++; + errors.append("Failed to delete appointment ID ").append(appointment.getAppointmentId()).append("\n"); + } + } + + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); + alert.showAndWait(); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText("Successfully deleted " + successCount + " appointment(s)"); + alert.showAndWait(); + } + + //refresh display loadAppointments(); - }catch(Exception e){ - ActivityLogger.getInstance().logException( - "AppointmentController.btnDeleteClicked", - e, - "Deleting appointment with ID: " + selected.getAppointmentId()); - e.printStackTrace(); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java index 96fa947a..3a7d9bcd 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java @@ -61,6 +61,8 @@ public class InventoryController { //Buttons disabled until row is selected btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId")); colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId")); @@ -101,64 +103,72 @@ public class InventoryController { //Prompts user for confirmation prior to deletion @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem(); + //get selected inventory records + var selectedInventory = tvInventory.getSelectionModel().getSelectedItems(); + if (selectedInventory.isEmpty()) return; - //Confirmation popup + //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 inventory record?"); + String message = selectedInventory.size() == 1 + ? "Are you sure you want to delete this inventory record?" + : "Are you sure you want to delete " + selectedInventory.size() + " inventory records?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); Optional result = question.showAndWait(); - //If user confirms, proceed with trying to delete... + //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int inventoryId = selectedInventory.getInventoryId(); + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - try { - numRows = InventoryDB.deleteInventory(inventoryId); + for (Inventory inventory : selectedInventory) { + try { + int numRows = InventoryDB.deleteInventory(inventory.getInventoryId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e) { + ActivityLogger.getInstance().logException( + "InventoryController.btnDeleteClicked", + e, + String.format("Attempting to delete inventory ID %d - foreign key constraint", inventory.getInventoryId())); + failCount++; + errors.append("Inventory record '").append(inventory.getProdName()).append("' is referenced in another table\n"); + } + catch (SQLException e) { + ActivityLogger.getInstance().logException( + "InventoryController.btnDeleteClicked", + e, + String.format("Attempting to delete inventory ID %d", inventory.getInventoryId())); + failCount++; + errors.append("Failed to delete '").append(inventory.getProdName()).append("'\n"); + } } - catch (SQLIntegrityConstraintViolationException e) { - ActivityLogger.getInstance().logException( - "InventoryController.btnDeleteClicked", - e, - "Deleting inventory (integrity constraint violation) with ID: " + inventoryId); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed\nThe selected inventory record is being referred in another table"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - return; - } - - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryController.btnDeleteClicked", - e, - "Deleting inventory with ID: " + inventoryId); - throw new RuntimeException(e); - } - - //Checks if deletion succeeded - if (numRows == 0) { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); - alert.showAndWait(); - } - - else { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " inventory record(s)"); alert.showAndWait(); - - //Refresh UI - displayInventory(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displayInventory(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/PetController.java b/src/main/java/org/example/petshopdesktop/controllers/PetController.java index ee987340..4874bea7 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PetController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PetController.java @@ -67,63 +67,72 @@ public class PetController { @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - Pet selectedPet = tvPets.getSelectionModel().getSelectedItem(); + //get selected pets + var selectedPets = tvPets.getSelectionModel().getSelectedItems(); + if (selectedPets.isEmpty()) return; //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?"); + String message = selectedPets.size() == 1 + ? "Are you sure you want to delete this pet?" + : "Are you sure you want to delete " + selectedPets.size() + " pets?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); - Optional result = question.showAndWait(); //show alert and wait for response + Optional result = question.showAndWait(); - //if confirmed,start deletion + //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int petId = selectedPet.getPetId(); + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - //try deleting - try{ - numRows = PetDB.deletePet(petId); - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "PetController.btnDeleteClicked", - e, - "Deleting pet (integrity constraint violation) with ID: " + petId); - 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) { - ActivityLogger.getInstance().logException( - "PetController.btnDeleteClicked", - e, - "Deleting pet with ID: " + petId); - throw new RuntimeException(e); + for (Pet pet : selectedPets) { + try{ + int numRows = PetDB.deletePet(pet.getPetId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e){ + ActivityLogger.getInstance().logException( + "PetController.btnDeleteClicked", + e, + String.format("Attempting to delete pet ID %d - foreign key constraint", pet.getPetId())); + failCount++; + errors.append("Pet '").append(pet.getPetName()).append("' is referenced in another table\n"); + } + catch (SQLException e) { + ActivityLogger.getInstance().logException( + "PetController.btnDeleteClicked", + e, + String.format("Attempting to delete pet ID %d", pet.getPetId())); + failCount++; + errors.append("Failed to delete '").append(pet.getPetName()).append("'\n"); + } } - //prompt user of any errors - if (numRows == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - } - else{ - //prompt user of delete conformation - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " pet(s)"); alert.showAndWait(); - //refresh display and reset inputs - displayPets(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displayPets(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } @@ -144,6 +153,8 @@ public class PetController { void initialize() { btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvPets.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colPetId.setCellValueFactory(new PropertyValueFactory("petId")); colPetName.setCellValueFactory(new PropertyValueFactory("petName")); diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index c39ca788..abc38be7 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -71,6 +71,8 @@ public class ProductController { //Disable buttons until a row is selected btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvProducts.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); //set up table columns colProductId.setCellValueFactory(new PropertyValueFactory("prodId")); colProductName.setCellValueFactory(new PropertyValueFactory("prodName")); @@ -137,69 +139,77 @@ public class ProductController { } /** - * Delete a selected product when delete is clicked + * Delete selected product(s) when delete is clicked * @param event click event for button */ @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - //set selected product - ProductDTO selectedProduct = tvProducts.getSelectionModel().getSelectedItem(); + //get selected products + var selectedProducts = tvProducts.getSelectionModel().getSelectedItems(); + if (selectedProducts.isEmpty()) return; //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 product?"); + String message = selectedProducts.size() == 1 + ? "Are you sure you want to delete this product?" + : "Are you sure you want to delete " + selectedProducts.size() + " products?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); - Optional result = question.showAndWait(); //show alert and wait for response + Optional result = question.showAndWait(); - //if confirmed,start deletion + //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int prodId = selectedProduct.getProdId(); + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - //try deleting - try{ - numRows = ProductDB.deleteProduct(prodId); - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductController.btnDeleteClicked", - e, - String.format("Attempting to delete product ID %d - foreign key constraint", prodId)); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed\n" + - "the selected product is being referred in another table"); - alert.showAndWait(); - return; - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductController.btnDeleteClicked", - e, - String.format("Attempting to delete product ID %d", prodId)); - throw new RuntimeException(e); + for (ProductDTO product : selectedProducts) { + try{ + int numRows = ProductDB.deleteProduct(product.getProdId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e){ + ActivityLogger.getInstance().logException( + "ProductController.btnDeleteClicked", + e, + String.format("Attempting to delete product ID %d - foreign key constraint", product.getProdId())); + failCount++; + errors.append("Product '").append(product.getProdName()).append("' is referenced in another table\n"); + } + catch (SQLException e) { + ActivityLogger.getInstance().logException( + "ProductController.btnDeleteClicked", + e, + String.format("Attempting to delete product ID %d", product.getProdId())); + failCount++; + errors.append("Failed to delete '").append(product.getProdName()).append("'\n"); + } } - //prompt user of any errors - if (numRows == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - } - else{ - //prompt user of delete conformation - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " product(s)"); alert.showAndWait(); - //refresh display and reset inputs - displayProduct(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displayProduct(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java index 64d3f513..ff5b3009 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java @@ -68,6 +68,8 @@ public class ProductSupplierController { //Disable buttons until a row is selected btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvProductSuppliers.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); //set up table columns colProductId.setCellValueFactory(new PropertyValueFactory("prodId")); colProductName.setCellValueFactory(new PropertyValueFactory("prodName")); @@ -158,70 +160,81 @@ public class ProductSupplierController { } /** - * Delete a selected productSupplier when delete is clicked + * Delete selected product-supplier(s) when delete is clicked * @param event click event for button */ @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - //set selected item - ProductSupplierDTO selectedProductSupplier = tvProductSuppliers.getSelectionModel().getSelectedItem(); + //get selected product-suppliers + var selectedProductSuppliers = tvProductSuppliers.getSelectionModel().getSelectedItems(); + if (selectedProductSuppliers.isEmpty()) return; //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 product-supplier?"); + String message = selectedProductSuppliers.size() == 1 + ? "Are you sure you want to delete this product-supplier?" + : "Are you sure you want to delete " + selectedProductSuppliers.size() + " product-suppliers?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); - Optional result = question.showAndWait(); //show alert and wait for response + Optional result = question.showAndWait(); - //if confirmed,start deletion + //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int supId = selectedProductSupplier.getSupId(); - int prodId = selectedProductSupplier.getProdId(); + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - //try deleting - try{ - numRows = ProductSupplierDB.deleteProductSupplier(supId, prodId); - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierController.btnDeleteClicked", - e, - "Deleting product-supplier (integrity constraint violation) - SupID: " + supId + ", ProdID: " + prodId); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed\n" + - "the selected product-supplier is being referred in another table"); - alert.showAndWait(); - return; - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductSupplierController.btnDeleteClicked", - e, - "Deleting product-supplier - SupID: " + supId + ", ProdID: " + prodId); - throw new RuntimeException(e); + for (ProductSupplierDTO productSupplier : selectedProductSuppliers) { + try{ + int numRows = ProductSupplierDB.deleteProductSupplier(productSupplier.getSupId(), productSupplier.getProdId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e){ + ActivityLogger.getInstance().logException( + "ProductSupplierController.btnDeleteClicked", + e, + String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d - foreign key constraint", + productSupplier.getSupId(), productSupplier.getProdId())); + failCount++; + errors.append(String.format("Product-Supplier '%s - %s' is referenced in another table\n", + productSupplier.getProdName(), productSupplier.getSupCompany())); + } + catch (SQLException e) { + ActivityLogger.getInstance().logException( + "ProductSupplierController.btnDeleteClicked", + e, + String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d", + productSupplier.getSupId(), productSupplier.getProdId())); + failCount++; + errors.append(String.format("Failed to delete '%s - %s'\n", + productSupplier.getProdName(), productSupplier.getSupCompany())); + } } - //prompt user of any errors - if (numRows == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - } - else{ - //prompt user of delete conformation - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " product-supplier(s)"); alert.showAndWait(); - //refresh display and reset inputs - displayProductSupplier(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displayProductSupplier(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java index 5d203dfe..2f5ae849 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java @@ -38,6 +38,8 @@ public class ServiceController { @FXML public void initialize() { + //Enable multiple selection + tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId")); colServiceName.setCellValueFactory(new PropertyValueFactory<>("serviceName")); @@ -124,19 +126,56 @@ public class ServiceController { @FXML void btnDeleteClicked(ActionEvent e) { + //get selected services + var selectedServices = tvServices.getSelectionModel().getSelectedItems(); + if (selectedServices.isEmpty()) return; - Service service = tvServices.getSelectionModel().getSelectedItem(); - if (service == null) return; + //ask user to confirm + Alert question = new Alert(Alert.AlertType.CONFIRMATION); + question.setHeaderText("Please confirm delete"); + String message = selectedServices.size() == 1 + ? "Are you sure you want to delete this service?" + : "Are you sure you want to delete " + selectedServices.size() + " services?"; + question.setContentText(message); + question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); + java.util.Optional result = question.showAndWait(); - try { - ServiceDB.deleteService(service.getServiceId()); + //if confirmed, start deletion + if (result.isPresent() && result.get() == ButtonType.OK) { + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); + + for (Service service : selectedServices) { + try { + ServiceDB.deleteService(service.getServiceId()); + successCount++; + } catch (Exception ex) { + ActivityLogger.getInstance().logException( + "ServiceController.btnDeleteClicked", + ex, + String.format("Attempting to delete service ID %d", service.getServiceId())); + failCount++; + errors.append("Failed to delete '").append(service.getServiceName()).append("'\n"); + } + } + + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); + alert.showAndWait(); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText("Successfully deleted " + successCount + " service(s)"); + alert.showAndWait(); + } + + //refresh display loadServices(); - } catch (Exception ex) { - ActivityLogger.getInstance().logException( - "ServiceController.btnDeleteClicked", - ex, - "Deleting service with ID: " + service.getServiceId()); - ex.printStackTrace(); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index a148c8da..049bddbd 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -66,6 +66,8 @@ public class SupplierController { //Disable buttons until a row is selected btnEdit.setDisable(true); btnDelete.setDisable(true); + //Enable multiple selection + tvSuppliers.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); //set columns for table view colSupplierId.setCellValueFactory(new PropertyValueFactory("supId")); colSupplierName.setCellValueFactory(new PropertyValueFactory("supCompany")); @@ -154,69 +156,77 @@ public class SupplierController { } /** - * Delete a selected supplier when delete is clicked + * Delete selected supplier(s) when delete is clicked * @param event click event for button */ @FXML void btnDeleteClicked(ActionEvent event) { - int numRows = 0; - //set selected supplier - Supplier selectedSupplier = tvSuppliers.getSelectionModel().getSelectedItem(); + //get selected suppliers + var selectedSuppliers = tvSuppliers.getSelectionModel().getSelectedItems(); + if (selectedSuppliers.isEmpty()) return; //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 supplier?"); + String message = selectedSuppliers.size() == 1 + ? "Are you sure you want to delete this supplier?" + : "Are you sure you want to delete " + selectedSuppliers.size() + " suppliers?"; + question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); - Optional result = question.showAndWait(); //show alert and wait for response + Optional result = question.showAndWait(); //if confirmed, start deletion - if (result.isPresent() && result.get() == ButtonType.OK){ - int supId = selectedSupplier.getSupId(); + if (result.isPresent() && result.get() == ButtonType.OK) { + int successCount = 0; + int failCount = 0; + StringBuilder errors = new StringBuilder(); - //Try deleting supplier - try{ - numRows = SupplierDB.deleteSupplier(supId); - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "SupplierController.btnDeleteClicked", - e, - "Deleting supplier (integrity constraint violation) with ID: " + supId); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed\n" + - "the selected supplier is being referred in another table"); - alert.showAndWait(); - return; - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "SupplierController.btnDeleteClicked", - e, - "Deleting supplier with ID: " + supId); - throw new RuntimeException(e); + for (Supplier supplier : selectedSuppliers) { + try{ + int numRows = SupplierDB.deleteSupplier(supplier.getSupId()); + if (numRows > 0) { + successCount++; + } else { + failCount++; + } + } + catch (SQLIntegrityConstraintViolationException e){ + ActivityLogger.getInstance().logException( + "SupplierController.btnDeleteClicked", + e, + String.format("Attempting to delete supplier ID %d - foreign key constraint", supplier.getSupId())); + failCount++; + errors.append("Supplier '").append(supplier.getSupCompany()).append("' is referenced in another table\n"); + } + catch (SQLException e) { + ActivityLogger.getInstance().logException( + "SupplierController.btnDeleteClicked", + e, + String.format("Attempting to delete supplier ID %d", supplier.getSupId())); + failCount++; + errors.append("Failed to delete '").append(supplier.getSupCompany()).append("'\n"); + } } - //prompt user of any errors - if (numRows == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Delete failed"); + //show results + if (failCount > 0) { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setHeaderText("Delete Operation Completed with Errors"); + alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", + successCount, failCount, errors.toString())); alert.showAndWait(); - } - else{ - //prompt user of delete conformation - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + } else if (successCount > 0) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Delete successful"); + alert.setContentText("Successfully deleted " + successCount + " supplier(s)"); alert.showAndWait(); - //refresh display - displaySupplier(); - btnDelete.setDisable(true); - btnEdit.setDisable(true); - txtSearch.setText(""); } + + //refresh display and reset inputs + displaySupplier(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } }