Modify Classroom and Course Schedule views to show generated schedule

This commit is contained in:
haxala1r
2025-12-18 15:30:23 +03:00
parent fcbd05edec
commit e53754d2a8
3 changed files with 107 additions and 89 deletions

View File

@@ -236,13 +236,13 @@ public class ExamEditDialog extends Dialog<ExamEditDialog.EditResult> {
validationPanel.setStyle("-fx-background-color: #e8f5e9; -fx-background-radius: 5;");
updateButtonStates(true, false);
} else if (currentValidation.hasHardViolations()) {
validationStatusLabel.setText("Constraint violations found");
validationStatusLabel.setText("Constraint violations found!");
validationStatusLabel.setTextFill(Color.web("#e74c3c"));
violationDetails.setText(currentValidation.getFormattedMessage());
validationPanel.setStyle("-fx-background-color: #ffebee; -fx-background-radius: 5;");
updateButtonStates(false, true);
} else {
validationStatusLabel.setText("⚠️ Warnings found");
validationStatusLabel.setText("Warnings found!");
validationStatusLabel.setTextFill(Color.web("#f39c12"));
violationDetails.setText(currentValidation.getFormattedMessage());
validationPanel.setStyle("-fx-background-color: #fff3e0; -fx-background-radius: 5;");

View File

@@ -11,14 +11,13 @@ import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import org.example.se302.model.Classroom;
import org.example.se302.model.ExamAssignment;
import org.example.se302.model.Course;
import org.example.se302.model.ScheduleConfiguration;
import org.example.se302.service.DataManager;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Map;
/**
* Controller for the Classroom Schedule view.
@@ -47,10 +46,6 @@ public class ScheduleClassroomController {
private DataManager dataManager;
// Reference to the current schedule state (set by parent controller)
private Map<String, ExamAssignment> currentAssignments;
private ScheduleConfiguration configuration;
@FXML
public void initialize() {
dataManager = DataManager.getInstance();
@@ -112,15 +107,35 @@ public class ScheduleClassroomController {
}
}
});
}
/**
* Sets the current schedule assignments. Called by parent controller after
* schedule generation.
*/
public void setScheduleData(Map<String, ExamAssignment> assignments, ScheduleConfiguration config) {
this.currentAssignments = assignments;
this.configuration = config;
// Refresh when tab is selected - find TabPane once scene is available
scheduleTable.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) {
// Find parent TabPane and listen for selection changes
javafx.scene.Parent parent = scheduleTable.getParent();
while (parent != null) {
if (parent.getParent() instanceof javafx.scene.control.TabPane) {
javafx.scene.control.TabPane tabPane = (javafx.scene.control.TabPane) parent
.getParent();
// Find which tab contains our content
for (javafx.scene.control.Tab tab : tabPane.getTabs()) {
if (tab.getContent() == parent) {
tab.selectedProperty().addListener(
(o, wasSelected, isSelected) -> {
if (isSelected && classroomComboBox
.getValue() != null) {
onShowSchedule();
}
});
break;
}
}
break;
}
parent = parent.getParent();
}
}
});
}
@FXML
@@ -132,40 +147,41 @@ public class ScheduleClassroomController {
selectedClassroomLabel.setText("Schedule for: " + selected.getClassroomId() +
" (Capacity: " + selected.getCapacity() + ")");
ScheduleConfiguration config = dataManager.getActiveConfiguration();
ObservableList<ClassroomSlotEntry> entries = FXCollections.observableArrayList();
int totalSlots = 0;
int usedSlots = 0;
int totalStudents = 0;
// If we have assignments, filter by this classroom
if (currentAssignments != null && !currentAssignments.isEmpty()) {
for (ExamAssignment assignment : currentAssignments.values()) {
if (assignment.isAssigned() &&
selected.getClassroomId().equals(assignment.getClassroomId())) {
// Find all courses scheduled in this classroom
for (Course course : dataManager.getCourses()) {
if (course.isScheduled() &&
selected.getClassroomId().equals(course.getAssignedClassroom())) {
int dayIndex = course.getExamDay();
int slotIndex = course.getExamTimeSlot();
// Format date
String dateStr;
if (configuration != null && configuration.getStartDate() != null) {
LocalDate examDate = configuration.getStartDate()
.plusDays(assignment.getDay());
if (config != null && config.getStartDate() != null) {
LocalDate examDate = config.getStartDate().plusDays(dayIndex);
dateStr = examDate.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} else {
dateStr = "Day " + (assignment.getDay() + 1);
dateStr = "Day " + (dayIndex + 1);
}
// Format time
String timeStr = "Slot " + (assignment.getTimeSlotIndex() + 1);
String timeStr = "Slot " + (slotIndex + 1);
// Calculate utilization percentage for this slot
int studentCount = assignment.getStudentCount();
// Calculate utilization
int studentCount = course.getEnrolledStudentsCount();
int capacity = selected.getCapacity();
int utilizationPercent = capacity > 0 ? (studentCount * 100) / capacity : 0;
String utilizationStr = utilizationPercent + "%";
entries.add(new ClassroomSlotEntry(
dateStr, timeStr, assignment.getCourseCode(),
dateStr, timeStr, course.getCourseCode(),
studentCount, utilizationStr, utilizationPercent,
assignment.getDay(), assignment.getTimeSlotIndex()));
dayIndex, slotIndex));
usedSlots++;
totalStudents += studentCount;
@@ -173,9 +189,8 @@ public class ScheduleClassroomController {
}
// Calculate total possible slots
if (configuration != null) {
totalSlots = configuration.getNumDays() * configuration.getSlotsPerDay();
}
if (config != null) {
totalSlots = config.getNumDays() * config.getSlotsPerDay();
}
// Sort by day then slot

View File

@@ -9,14 +9,12 @@ import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import org.example.se302.model.Course;
import org.example.se302.model.ExamAssignment;
import org.example.se302.model.ScheduleConfiguration;
import org.example.se302.service.DataManager;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Map;
// Color palette for days (pastel colors for readability)
// Day 0 = Light Blue, Day 1 = Light Green, Day 2 = Light Yellow, etc.
@@ -43,11 +41,6 @@ public class ScheduleCourseController {
private DataManager dataManager;
// Reference to the current schedule state (set by parent controller or loaded
// from DB)
private Map<String, ExamAssignment> currentAssignments;
private ScheduleConfiguration configuration;
@FXML
public void initialize() {
dataManager = DataManager.getInstance();
@@ -122,19 +115,38 @@ public class ScheduleCourseController {
// Listen for data changes
dataManager.getCourses().addListener(
(javafx.collections.ListChangeListener<Course>) c -> loadScheduleData());
}
/**
* Sets the current schedule assignments. Called by parent controller after
* schedule generation.
*/
public void setScheduleData(Map<String, ExamAssignment> assignments, ScheduleConfiguration config) {
this.currentAssignments = assignments;
this.configuration = config;
// Refresh when tab is selected - find TabPane once scene is available
courseScheduleTable.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) {
loadScheduleData();
// Find parent TabPane and listen for selection changes
javafx.scene.Parent parent = courseScheduleTable.getParent();
while (parent != null) {
if (parent.getParent() instanceof javafx.scene.control.TabPane) {
javafx.scene.control.TabPane tabPane = (javafx.scene.control.TabPane) parent
.getParent();
// Find which tab contains our content
for (javafx.scene.control.Tab tab : tabPane.getTabs()) {
if (tab.getContent() == parent) {
tab.selectedProperty().addListener(
(o, wasSelected, isSelected) -> {
if (isSelected)
loadScheduleData();
});
break;
}
}
break;
}
parent = parent.getParent();
}
}
});
}
private void loadScheduleData() {
ScheduleConfiguration config = dataManager.getActiveConfiguration();
ObservableList<CourseScheduleEntry> entries = FXCollections.observableArrayList();
for (Course course : dataManager.getCourses()) {
@@ -144,33 +156,24 @@ public class ScheduleCourseController {
String dateStr = "Not Scheduled";
String timeStr = "-";
String classroomStr = "-";
int dayIndex = Integer.MAX_VALUE; // For sorting unscheduled items last
int dayIndex = Integer.MAX_VALUE;
int slotIndex = Integer.MAX_VALUE;
// Check if we have an assignment for this course
if (currentAssignments != null && currentAssignments.containsKey(courseCode)) {
ExamAssignment assignment = currentAssignments.get(courseCode);
// Check if this course has been scheduled
if (course.isScheduled()) {
dayIndex = course.getExamDay();
slotIndex = course.getExamTimeSlot();
classroomStr = course.getAssignedClassroom();
if (assignment.isAssigned()) {
dayIndex = assignment.getDay();
slotIndex = assignment.getTimeSlotIndex();
// Format date based on configuration start date + day offset
if (configuration != null && configuration.getStartDate() != null) {
LocalDate examDate = configuration.getStartDate().plusDays(dayIndex);
dateStr = examDate.format(
DateTimeFormatter.ofPattern("dd/MM/yyyy (EEEE)"));
// Format date using configuration's start date
if (config != null && config.getStartDate() != null) {
LocalDate examDate = config.getStartDate().plusDays(dayIndex);
dateStr = examDate.format(DateTimeFormatter.ofPattern("dd/MM/yyyy (EEEE)"));
} else {
dateStr = "Day " + (dayIndex + 1);
}
// Format time slot
timeStr = "Slot " + (slotIndex + 1);
// Classroom
classroomStr = assignment.getClassroomId() != null ? assignment.getClassroomId()
: "-";
}
}
entries.add(new CourseScheduleEntry(courseCode, enrolled, dateStr, timeStr, classroomStr,