0% found this document useful (0 votes)
8 views9 pages

Select Ex Ma

The SelectExamPanel class is a Java Swing component that allows students to view and manage their available exams. It features a table displaying exam details, buttons to start an exam or request a retake, and a status label for user feedback. The panel connects to a database to fetch exam data and updates the UI based on the student's selections and exam statuses.

Uploaded by

panditpuspa000
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views9 pages

Select Ex Ma

The SelectExamPanel class is a Java Swing component that allows students to view and manage their available exams. It features a table displaying exam details, buttons to start an exam or request a retake, and a status label for user feedback. The panel connects to a database to fetch exam data and updates the UI based on the student's selections and exam statuses.

Uploaded by

panditpuspa000
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

package student;

import db.DBConnection;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.Vector;
import java.util.List;
import java.util.ArrayList;

public class SelectExamPanel extends JPanel {

private final int studentId;


private final StudentDashboard parentDashboard;

private JTable examTable;


private DefaultTableModel tableModel;
private JButton takeExamButton;
private JButton requestRetakeButton;
private JLabel statusLabel;

private ScheduledExecutorService scheduler;

// --- Consistent Color Palette ---


private static final Color MAIN_BG = new Color(240, 242, 245);
private static final Color HEADER_TEXT = new Color(52, 73, 94);
private static final Color TABLE_HEADER_BG = new Color(66, 133, 244);
private static final Color TABLE_HEADER_TEXT = Color.WHITE;
private static final Color BUTTON_PRIMARY_NORMAL = new Color(46, 139, 87);
private static final Color BUTTON_PRIMARY_HOVER = new Color(34, 102, 68);
private static final Color BUTTON_REQUEST_NORMAL = new Color(255, 165, 0);
private static final Color BUTTON_REQUEST_HOVER = new Color(204, 133, 0);
private static final Color BUTTON_DISABLED = new Color(150, 150, 150);
private static final Color STATUS_READY = new Color(200, 255, 200);
private static final Color STATUS_TAKEN = new Color(255, 220, 150);
private static final Color STATUS_NOT_ALLOWED = new Color(255, 180, 180);
private static final Color STATUS_PENDING_REQUEST = new Color(173, 216, 230);

public SelectExamPanel(int studentId, StudentDashboard parentDashboard) {


this.studentId = studentId;
this.parentDashboard = parentDashboard;
setLayout(new BorderLayout(20, 20));
setBorder(new EmptyBorder(30, 30, 30, 30));
setBackground(MAIN_BG);

// --- Heading ---


JLabel heading = new JLabel("📚 Available Exams for " +
getStudentName(studentId), JLabel.CENTER);
heading.setFont(new Font("Segoe UI", Font.BOLD, 32));
heading.setForeground(HEADER_TEXT);
add(heading, BorderLayout.NORTH);

// --- Table Setup ---


String[] columnNames = {"Exam ID", "Exam Title", "Duration (mins)", "Your
Attempts", "Max Attempts", "Status", "Actions"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}

@Override
public Class<?> getColumnClass(int columnIndex) {
return switch (columnIndex) {
case 0, 2, 3, 4 -> Integer.class;
default -> String.class;
};
}
};

examTable = new JTable(tableModel);


examTable.setFillsViewportHeight(true);
examTable.setRowHeight(35);
examTable.getTableHeader().setFont(new Font("Segoe UI", Font.BOLD, 15));
examTable.getTableHeader().setBackground(TABLE_HEADER_BG);
examTable.getTableHeader().setForeground(TABLE_HEADER_TEXT);
examTable.getTableHeader().setReorderingAllowed(false);
examTable.setFont(new Font("Segoe UI", Font.PLAIN, 14));
examTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
examTable.setAutoCreateRowSorter(true);

examTable.setSelectionBackground(new Color(190, 220, 255));


examTable.setSelectionForeground(Color.BLACK);
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(JLabel.CENTER);
examTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
examTable.getColumnModel().getColumn(2).setCellRenderer(centerRenderer);
examTable.getColumnModel().getColumn(3).setCellRenderer(centerRenderer);
examTable.getColumnModel().getColumn(4).setCellRenderer(centerRenderer);
examTable.getColumnModel().getColumn(5).setCellRenderer(new
DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object
value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
if (value != null) {
String status = value.toString();
switch (status) {
case "Ready":
label.setBackground(STATUS_READY);
break;
case "Taken":
label.setBackground(STATUS_TAKEN);
break;
case "Not Allowed":
label.setBackground(STATUS_NOT_ALLOWED);
break;
case "Request Pending":
label.setBackground(STATUS_PENDING_REQUEST);
break;
default:
label.setBackground(table.getBackground());
}
}
label.setHorizontalAlignment(SwingConstants.CENTER);
return label;
}
});

JScrollPane scrollPane = new JScrollPane(examTable);


scrollPane.setBorder(BorderFactory.createLineBorder(new Color(180, 180,
180), 1));
scrollPane.getViewport().setBackground(Color.WHITE);
add(scrollPane, BorderLayout.CENTER);

// --- Button Panel ---


JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
buttonPanel.setOpaque(false);

takeExamButton = new JButton("Start Exam");


styleButton(takeExamButton, BUTTON_PRIMARY_NORMAL);
takeExamButton.setEnabled(false);
buttonPanel.add(takeExamButton);

requestRetakeButton = new JButton("Request Retake");


styleButton(requestRetakeButton, BUTTON_REQUEST_NORMAL);
requestRetakeButton.setEnabled(false);
buttonPanel.add(requestRetakeButton);
add(buttonPanel, BorderLayout.SOUTH);

// --- Status Label (bottom left) ---


statusLabel = new JLabel("Loading exams...", JLabel.LEFT);
statusLabel.setFont(new Font("Segoe UI", Font.ITALIC, 12));
statusLabel.setForeground(Color.DARK_GRAY);
JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
statusPanel.setOpaque(false);
statusPanel.add(statusLabel);

// Add action listeners


examTable.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
updateButtonStates();
}
});

takeExamButton.addActionListener(e -> startExam());


requestRetakeButton.addActionListener(e -> requestRetake());

loadAvailableExams(false);
setupAccessMonitor();
}

private String getStudentName(int studentId) {


String studentName = "Student";
try (Connection con = DBConnection.getConnection();
PreparedStatement pst = con.prepareStatement("SELECT name FROM
students WHERE student_id = ?")) {
pst.setInt(1, studentId);
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
studentName = rs.getString("name");
}
}
} catch (SQLException e) {
System.err.println("Error fetching student name: " + e.getMessage());
}
return studentName;
}

private void styleButton(JButton button, Color normalColor) {


button.setFont(new Font("Segoe UI", Font.BOLD, 16));
button.setBackground(normalColor);
button.setForeground(Color.WHITE);
button.setFocusPainted(false);
button.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(normalColor.darker(), 1),
new EmptyBorder(10, 25, 10, 25)
));
button.setCursor(new Cursor(Cursor.HAND_CURSOR));

button.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
if (button.isEnabled()) {
if (button == takeExamButton)
button.setBackground(BUTTON_PRIMARY_HOVER);
else if (button == requestRetakeButton)
button.setBackground(BUTTON_REQUEST_HOVER);
}
}

public void mouseExited(java.awt.event.MouseEvent evt) {


if (button.isEnabled()) {
button.setBackground(normalColor);
} else {
button.setBackground(BUTTON_DISABLED);
}
}
});
}

public void loadAvailableExams(boolean silent) {


tableModel.setRowCount(0);
takeExamButton.setEnabled(false);
requestRetakeButton.setEnabled(false);
statusLabel.setText("Refreshing exam list...");

try (Connection con = DBConnection.getConnection()) {


String query = """
SELECT
e.exam_id,
e.title,
e.duration,
COALESCE(sea.is_allowed, FALSE) AS is_allowed,
COALESCE(sea.attempts_taken, 0) AS attempts_taken,
COALESCE(e.max_attempts, 1) AS max_attempts,
(SELECT status FROM exam_retake_requests err WHERE
err.student_id = ? AND err.exam_id = e.exam_id AND err.status = 'Pending' LIMIT 1)
AS pending_request_status
FROM
exams e
LEFT JOIN
student_exam_access sea ON e.exam_id = sea.exam_id AND
sea.student_id = ?
WHERE
e.is_enabled = TRUE AND e.status = 'enabled'
ORDER BY
e.title ASC;
""";
PreparedStatement pst = con.prepareStatement(query);
pst.setInt(1, studentId);
pst.setInt(2, studentId);
ResultSet rs = pst.executeQuery();

boolean examsFound = false;


while (rs.next()) {
examsFound = true;
int examId = rs.getInt("exam_id");
String title = rs.getString("title");
int duration = rs.getInt("duration");
boolean isAllowed = rs.getBoolean("is_allowed");
int attemptsTaken = rs.getInt("attempts_taken");
int maxAttempts = rs.getInt("max_attempts");
String pendingRequestStatus =
rs.getString("pending_request_status");

// --- START DEBUG PRINTS ---


System.out.println("--- Debug Info for Exam ID: " + examId + "
---");
System.out.println("isAllowed (from DB): " + isAllowed);
System.out.println("attemptsTaken (from DB): " + attemptsTaken);
System.out.println("maxAttempts (from DB): " + maxAttempts);
System.out.println("pendingRequestStatus (from DB): " +
pendingRequestStatus);
// --- END DEBUG PRINTS ---

String status;
if (pendingRequestStatus != null &&
pendingRequestStatus.equals("Pending")) {
status = "Request Pending";
} else if (isAllowed && (attemptsTaken < maxAttempts || maxAttempts
== 0)) {
status = "Ready";
} else if (!isAllowed && attemptsTaken == maxAttempts) {
status = "Taken";
} else if (!isAllowed && attemptsTaken < maxAttempts) {
status = "Not Allowed";
} else {
status = "Taken";
}

// --- START DEBUG PRINTS ---


System.out.println("Calculated Status: " + status);
System.out.println("------------------------------------");
// --- END DEBUG PRINTS ---

tableModel.addRow(new Object[]{
examId,
title,
duration,
attemptsTaken,
maxAttempts,
status
});
}

// --- START OF NEW CODE TO AUTOMATICALLY SELECT APPROVED EXAM ---


int readyExamRowIndex = -1;
int readyExamCount = 0;

for (int i = 0; i < tableModel.getRowCount(); i++) {


// Ensure to convert row index from view to model if sorting is
active
int modelRow = examTable.convertRowIndexToModel(i);
String status = (String) tableModel.getValueAt(modelRow, 5); //
Assuming status is at column index 5
if ("Ready".equals(status)) {
readyExamCount++;
readyExamRowIndex = i; // Store the view row index
}
}

if (readyExamCount == 1) {
// Automatically select the row if there's exactly one "Ready" exam
final int finalReadyExamRowIndex = readyExamRowIndex; // For use in
SwingUtilities.invokeLater
SwingUtilities.invokeLater(() -> {
examTable.setRowSelectionInterval(finalReadyExamRowIndex,
finalReadyExamRowIndex);
// updateButtonStates() will be called in the finally block,
which will enable the button.
});
statusLabel.setText("Your approved exam is ready to start. Click
'Start Exam'!");
} else if (examsFound) {
statusLabel.setText("Exams loaded. Select an exam to view
options.");
} else {
statusLabel.setText("No exams available at the moment.");
}
// --- END OF NEW CODE TO AUTOMATICALLY SELECT APPROVED EXAM ---

} catch (SQLException e) {
if (!silent) {
JOptionPane.showMessageDialog(this, "Error loading exams: " +
e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);
}
statusLabel.setText("Error loading exams.");
e.printStackTrace();
} catch (Exception e) {
if (!silent) {
JOptionPane.showMessageDialog(this, "An unexpected error occurred:
" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
statusLabel.setText("Error loading exams.");
e.printStackTrace();
} finally {
updateButtonStates();
}
}

private void updateButtonStates() {


int selectedRow = examTable.getSelectedRow();
boolean enableTakeExam = false;
boolean enableRequestRetake = false;

if (selectedRow != -1) {
int modelRow = examTable.convertRowIndexToModel(selectedRow);
String status = (String) tableModel.getValueAt(modelRow, 5);
int attemptsTaken = (int) tableModel.getValueAt(modelRow, 3);
int maxAttempts = (int) tableModel.getValueAt(modelRow, 4);
if ("Ready".equals(status)) {
enableTakeExam = true;
} else if ("Taken".equals(status) || "Not Allowed".equals(status)) {
if (attemptsTaken >= maxAttempts) {
enableRequestRetake = true;
}
}
}

takeExamButton.setEnabled(enableTakeExam);
requestRetakeButton.setEnabled(enableRequestRetake);

styleButton(takeExamButton, enableTakeExam ? BUTTON_PRIMARY_NORMAL :


BUTTON_DISABLED);
styleButton(requestRetakeButton, enableRequestRetake ?
BUTTON_REQUEST_NORMAL : BUTTON_DISABLED);
}

private void startExam() {


int selectedRow = examTable.getSelectedRow();
if (selectedRow == -1) {
JOptionPane.showMessageDialog(this, "Please select an exam to start.",
"No Exam Selected", JOptionPane.WARNING_MESSAGE);
return;
}

int modelRow = examTable.convertRowIndexToModel(selectedRow);


int examId = (int) tableModel.getValueAt(modelRow, 0);
String status = (String) tableModel.getValueAt(modelRow, 5);
if (!"Ready".equals(status)) {
JOptionPane.showMessageDialog(this, "This exam is not currently
available for taking. Status: " + status, "Exam Not Ready",
JOptionPane.WARNING_MESSAGE);
loadAvailableExams(false);
return;
}

List<Integer> examIdsInSession = new ArrayList<>();


examIdsInSession.add(examId);
int confirm = JOptionPane.showConfirmDialog(this,
"Are you sure you want to start the selected exam?",
"Confirm Start Exam", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
stopAccessMonitor();
TakeExamPanel takeExamPanel = new TakeExamPanel(studentId,
examIdsInSession, parentDashboard);
parentDashboard.setMainContent(takeExamPanel, "Exam Session");
}
}

private void requestRetake() {


int selectedRow = examTable.getSelectedRow();
if (selectedRow == -1) {
JOptionPane.showMessageDialog(this, "Please select an exam to request a
retake for.", "No Exam Selected", JOptionPane.WARNING_MESSAGE);
return;
}

int modelRow = examTable.convertRowIndexToModel(selectedRow);


int examId = (int) tableModel.getValueAt(modelRow, 0);
String examTitle = (String) tableModel.getValueAt(modelRow, 1);
String currentStatus = (String) tableModel.getValueAt(modelRow, 5);
if (currentStatus.equals("Request Pending")) {
JOptionPane.showMessageDialog(this, "A retake request for '" +
examTitle + "' is already pending review.", "Request Already Pending",
JOptionPane.INFORMATION_MESSAGE);
return;
}
if (currentStatus.equals("Ready")) {
JOptionPane.showMessageDialog(this, "You are already allowed to take '"
+ examTitle + "'. No retake request needed.", "Exam Already Ready",
JOptionPane.INFORMATION_MESSAGE);
return;
}

int confirm = JOptionPane.showConfirmDialog(this,


"<html>Are you sure you want to request a retake for **" +
examTitle + "**?<br>" +
"Your request will be sent to the examiner for
review.</html>",
"Confirm Retake Request", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (confirm == JOptionPane.YES_OPTION) {
try (Connection con = DBConnection.getConnection()) {
String checkQuery = "SELECT request_id, status FROM
exam_retake_requests WHERE student_id = ? AND exam_id = ? LIMIT 1";
PreparedStatement checkPst = con.prepareStatement(checkQuery);
checkPst.setInt(1, studentId);
checkPst.setInt(2, examId);
ResultSet checkRs = checkPst.executeQuery();
if (checkRs.next()) {
String existingStatus = checkRs.getString("status");
int existingRequestId = checkRs.getInt("request_id");

if ("Denied".equals(existingStatus)) {
String updateQuery = "UPDATE exam_retake_requests SET
status = 'Pending', request_date = NOW(), response_date = NULL, examiner_notes =
NULL WHERE request_id = ?";
PreparedStatement updatePst =
con.prepareStatement(updateQuery);
updatePst.setInt(1, existingRequestId);
updatePst.executeUpdate();
JOptionPane.showMessageDialog(this, "Your retake request
for '" + examTitle + "' has been re-submitted to the examiner.", "Request Re-
submitted", JOptionPane.INFORMATION_MESSAGE);
} else if ("Granted".equals(existingStatus)) {
JOptionPane.showMessageDialog(this, "You have already been
granted access for '" + examTitle + "'. Please check the 'Ready' status.", "Access
Already Granted", JOptionPane.INFORMATION_MESSAGE);
} else if ("Pending".equals(existingStatus)) {
JOptionPane.showMessageDialog(this, "A retake request for
'" + examTitle + "' is already pending review.", "Request Already Pending",
JOptionPane.INFORMATION_MESSAGE);
}
} else {
String insertQuery = "INSERT INTO exam_retake_requests
(student_id, exam_id, request_date, status) VALUES (?, ?, NOW(), 'Pending')";
PreparedStatement insertPst =
con.prepareStatement(insertQuery);
insertPst.setInt(1, studentId);
insertPst.setInt(2, examId);
insertPst.executeUpdate();
JOptionPane.showMessageDialog(this, "Your retake request for '"
+ examTitle + "' has been submitted to the examiner.", "Request Submitted",
JOptionPane.INFORMATION_MESSAGE);
}
loadAvailableExams(false);
} catch (SQLException e) {
JOptionPane.showMessageDialog(this, "Error submitting retake
request: " + e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}
}

public void setupAccessMonitor() {


if (scheduler != null && !scheduler.isShutdown()) {
return;
}
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> SwingUtilities.invokeLater(() -> {
loadAvailableExams(true);
}), 0, 60, TimeUnit.SECONDS);
}

public void stopAccessMonitor() {


if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdownNow();
scheduler = null;
}
}
}

You might also like