Add error dialog for view loading failures and fix btnPurchaseOrdersClicked signature
This commit is contained in:
@@ -5,16 +5,14 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
/*
|
|
||||||
Petshop Desktop
|
|
||||||
Purpose: Main application shell controller, includes navigation and UI level role based access control.
|
|
||||||
*/
|
|
||||||
public class MainLayoutController {
|
public class MainLayoutController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -50,6 +48,9 @@ public class MainLayoutController {
|
|||||||
@FXML
|
@FXML
|
||||||
private Button btnSuppliers;
|
private Button btnSuppliers;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button btnStaffAccounts;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label lblUsername;
|
private Label lblUsername;
|
||||||
|
|
||||||
@@ -102,11 +103,17 @@ public class MainLayoutController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnPurchaseOrdersClicked() {
|
void btnPurchaseOrdersClicked(ActionEvent event) {
|
||||||
loadView("purchase-order-view.fxml");
|
loadView("purchase-order-view.fxml");
|
||||||
updateButtons(btnPurchaseOrders);
|
updateButtons(btnPurchaseOrders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void btnStaffAccountsClicked(ActionEvent event) {
|
||||||
|
loadView("staff-accounts-view.fxml");
|
||||||
|
updateButtons(btnStaffAccounts);
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnServicesClicked(ActionEvent event) {
|
void btnServicesClicked(ActionEvent event) {
|
||||||
loadView("service-view.fxml");
|
loadView("service-view.fxml");
|
||||||
@@ -117,14 +124,10 @@ public class MainLayoutController {
|
|||||||
void btnSuppliersClicked(ActionEvent event) {
|
void btnSuppliersClicked(ActionEvent event) {
|
||||||
loadView("supplier-view.fxml");
|
loadView("supplier-view.fxml");
|
||||||
updateButtons(btnSuppliers);
|
updateButtons(btnSuppliers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnLogoutClicked(ActionEvent event) {
|
void btnLogoutClicked(ActionEvent event) {
|
||||||
// Logout clears session state before returning to the login view.
|
|
||||||
UserSession.getInstance().logout();
|
UserSession.getInstance().logout();
|
||||||
try {
|
try {
|
||||||
FXMLLoader loader = new FXMLLoader(
|
FXMLLoader loader = new FXMLLoader(
|
||||||
@@ -134,6 +137,10 @@ public class MainLayoutController {
|
|||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.setTitle("Pet Shop Manager - Login");
|
stage.setTitle("Pet Shop Manager - Login");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"MainLayoutController.btnLogoutClicked",
|
||||||
|
e,
|
||||||
|
"Loading login view after logout");
|
||||||
System.err.println("Error loading login view: " + e.getMessage());
|
System.err.println("Error loading login view: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -141,22 +148,22 @@ public class MainLayoutController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
// RBAC state is applied once during initial layout load.
|
|
||||||
applyRBAC();
|
applyRBAC();
|
||||||
|
|
||||||
// Default landing view after successful authentication.
|
|
||||||
loadView("pet-view.fxml");
|
loadView("pet-view.fxml");
|
||||||
|
updateButtons(btnPets);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyRBAC() {
|
private void applyRBAC() {
|
||||||
UserSession session = UserSession.getInstance();
|
UserSession session = UserSession.getInstance();
|
||||||
|
|
||||||
// Session identity is displayed in the header for clarity and auditing.
|
String displayName = session.getEmployeeName();
|
||||||
lblUsername.setText(session.getUsername());
|
if (displayName == null || displayName.isBlank()) {
|
||||||
lblRole.setText(session.getRole().toString());
|
displayName = session.getUsername();
|
||||||
|
}
|
||||||
|
lblUsername.setText(displayName == null ? "" : displayName);
|
||||||
|
lblRole.setText("Leon's Petstore");
|
||||||
|
|
||||||
// UI level RBAC hides admin only navigation entries for non admin users.
|
|
||||||
// setManaged(false) removes the node from layout calculations to avoid empty spacing.
|
|
||||||
boolean isAdmin = session.isAdmin();
|
boolean isAdmin = session.isAdmin();
|
||||||
btnInventory.setVisible(isAdmin);
|
btnInventory.setVisible(isAdmin);
|
||||||
btnInventory.setManaged(isAdmin);
|
btnInventory.setManaged(isAdmin);
|
||||||
@@ -165,47 +172,65 @@ public class MainLayoutController {
|
|||||||
btnProductSuppliers.setVisible(isAdmin);
|
btnProductSuppliers.setVisible(isAdmin);
|
||||||
btnProductSuppliers.setManaged(isAdmin);
|
btnProductSuppliers.setManaged(isAdmin);
|
||||||
|
|
||||||
// Privileged operations should still be enforced within the relevant controllers and database methods.
|
btnPurchaseOrders.setVisible(isAdmin);
|
||||||
|
btnPurchaseOrders.setManaged(isAdmin);
|
||||||
|
|
||||||
|
btnStaffAccounts.setVisible(isAdmin);
|
||||||
|
btnStaffAccounts.setManaged(isAdmin);
|
||||||
|
|
||||||
|
btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a view when a button is clicked on the navigation
|
|
||||||
* @param fxmlFile the fxmlFile name to be loaded
|
|
||||||
*/
|
|
||||||
private void loadView(String fxmlFile) {
|
private void loadView(String fxmlFile) {
|
||||||
try {
|
try {
|
||||||
//Get the location of the fxml for view
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/modelviews/" + fxmlFile));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/modelviews/" + fxmlFile));
|
||||||
Parent view = loader.load();
|
Parent view = loader.load();
|
||||||
//Clear any content that is in the stack pane and add the new view to display
|
|
||||||
spContentArea.getChildren().clear();
|
spContentArea.getChildren().clear();
|
||||||
spContentArea.getChildren().add(view);
|
spContentArea.getChildren().add(view);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"MainLayoutController.loadView",
|
||||||
|
e,
|
||||||
|
"Loading view: " + fxmlFile);
|
||||||
System.err.println("Error loading view: " + fxmlFile);
|
System.err.println("Error loading view: " + fxmlFile);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("View Load Error");
|
||||||
|
alert.setHeaderText("Failed to load: " + fxmlFile);
|
||||||
|
alert.setContentText("Error: " + e.getMessage() + "\n\nCheck console for details.");
|
||||||
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* update the button visuals when a button is clicked on the navigation
|
|
||||||
* @param activeButton the button to be set active
|
|
||||||
*/
|
|
||||||
private void updateButtons(Button activeButton) {
|
private void updateButtons(Button activeButton) {
|
||||||
//reset all buttons
|
String base = "-fx-background-color: transparent; -fx-text-fill: #D5DDE6; -fx-cursor: hand; -fx-background-radius: 10; -fx-alignment: CENTER_LEFT;";
|
||||||
Button[] BUTTONS = {btnAdoptions, btnPets, btnAppointments, btnInventory,
|
String active = "-fx-background-color: #FF6B6B; -fx-text-fill: white; -fx-cursor: hand; -fx-background-radius: 10; -fx-alignment: CENTER_LEFT;";
|
||||||
btnSalesHistory, btnServices, btnSuppliers, btnProductSuppliers, btnProducts};
|
|
||||||
for (Button button : BUTTONS) {
|
Button[] buttons = {
|
||||||
//set all buttons to inactive
|
btnAdoptions,
|
||||||
button.setStyle("-fx-background-color: transparent; " +
|
btnPets,
|
||||||
"-fx-text-fill: #CCCCCC; " +
|
btnAppointments,
|
||||||
"-fx-cursor: hand");
|
btnInventory,
|
||||||
|
btnSalesHistory,
|
||||||
|
btnServices,
|
||||||
|
btnSuppliers,
|
||||||
|
btnProductSuppliers,
|
||||||
|
btnProducts,
|
||||||
|
btnPurchaseOrders,
|
||||||
|
btnStaffAccounts
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Button button : buttons) {
|
||||||
|
if (button != null) {
|
||||||
|
button.setStyle(base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//set active button
|
if (activeButton != null) {
|
||||||
activeButton.setStyle("-fx-background-color: #FF6B6B; " +
|
activeButton.setStyle(active);
|
||||||
"-fx-text-fill: white; " +
|
}
|
||||||
"-fx-cursor: hand; " +
|
|
||||||
"-fx-background-radius: 8");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user