diff --git a/checkup_details.pdf b/checkup_details.pdf new file mode 100644 index 0000000..3eb1ced --- /dev/null +++ b/checkup_details.pdf @@ -0,0 +1,83 @@ +%PDF-1.4 +%öäüß +1 0 obj +<< +/Type /Catalog +/Version /1.4 +/Pages 2 0 R +>> +endobj +2 0 obj +<< +/Type /Pages +/Kids [3 0 R] +/Count 1 +>> +endobj +3 0 obj +<< +/Type /Page +/MediaBox [0.0 0.0 595.27563 841.8898] +/Parent 2 0 R +/Contents 4 0 R +/Resources 5 0 R +>> +endobj +4 0 obj +<< +/Length 260 +/Filter /FlateDecode +>> +stream +xœu‘ÁRà E÷|Å[tQi€�f§Å:uÔq,ãžI_4'¡~¿Ô$“º`Ã=¼—xÍ€qPaéB€z 7Š +Wa©™?koÐzØØÂe ÞȭꑤEžô3¸w¥é𛡵ãB¼‘Y0$©˜$×ûp.™ìÿ +X+¸C‹µ®ÎÝárÙ"¯¦1¤öa"§\D”Et91J—{Wg ëlÆ—gÜñšÃI\ôŠ®‰-ÖŸ&Çøw&7áL¢×¦ji:HW®ñ}ŸªŠ’ž±Í±ò¡xgÇ’äo#«ó÷ãÇXÖQ3AGmu…þ÷Öÿ¹±ð‚•Áb<¹#fügò“öŒq +endstream +endobj +5 0 obj +<< +/Font 6 0 R +>> +endobj +6 0 obj +<< +/F1 7 0 R +/F2 8 0 R +>> +endobj +7 0 obj +<< +/Type /Font +/Subtype /Type1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding +>> +endobj +8 0 obj +<< +/Type /Font +/Subtype /Type1 +/BaseFont /Helvetica-Bold +/Encoding /WinAnsiEncoding +>> +endobj +xref +0 9 +0000000000 65535 f +0000000015 00000 n +0000000078 00000 n +0000000135 00000 n +0000000254 00000 n +0000000588 00000 n +0000000621 00000 n +0000000662 00000 n +0000000759 00000 n +trailer +<< +/Root 1 0 R +/ID [<0D096FE5232DC05955FD1862642B6A74> <0D096FE5232DC05955FD1862642B6A74>] +/Size 9 +>> +startxref +861 +%%EOF diff --git a/medical_invoice.pdf b/medical_invoice.pdf new file mode 100644 index 0000000..29a5c56 Binary files /dev/null and b/medical_invoice.pdf differ diff --git a/pom.xml b/pom.xml index 5e89c79..cfeca41 100644 --- a/pom.xml +++ b/pom.xml @@ -116,6 +116,24 @@ 1.6.1 + + com.itextpdf + itextpdf + 5.5.13.2 + + + + org.apache.pdfbox + pdfbox + 2.0.27 + + + + com.itextpdf + itext7-core + 7.1.12 + pom + diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java index dcf8e2b..57ee088 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java @@ -3,7 +3,8 @@ package BsK.client.ui.component.CheckUpPage; import BsK.client.LocalStorage; import BsK.client.network.handler.ClientHandler; import BsK.client.network.handler.ResponseListener; -import BsK.client.ui.component.CheckUpPage.MedicineWindow.MedicineDialog; +import BsK.client.ui.component.CheckUpPage.MedicineDialog.MedicineDialog; +import BsK.client.ui.component.CheckUpPage.ServiceDialog.ServiceDialog; import BsK.client.ui.component.MainFrame; import BsK.client.ui.component.common.DateLabelFormatter; import BsK.client.ui.component.common.RoundedPanel; @@ -19,6 +20,8 @@ import lombok.extern.slf4j.Slf4j; import org.jdatepicker.impl.JDatePanelImpl; import org.jdatepicker.impl.JDatePickerImpl; import org.jdatepicker.impl.UtilDateModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.swing.*; import javax.swing.table.DefaultTableModel; @@ -34,6 +37,7 @@ import java.util.Properties; @Slf4j public class CheckUpPage extends JPanel { + private static final Logger log = LoggerFactory.getLogger(CheckUpPage.class); private String[][] queue; private String[][] history; private DefaultTableModel model, historyModel; @@ -47,11 +51,13 @@ public class CheckUpPage extends JPanel { private JComboBox doctorComboBox, statusComboBox; private JDatePickerImpl datePicker; private String[][] medicinePrescription; + private String[][] servicePrescription; private String[] doctorOptions; - private MedicineDialog dialog = null; + private MedicineDialog medDialog = null; + private ServiceDialog serDialog = null; private int previousSelectedRow = -1; private boolean saved = false; - + boolean returnCell = false; public void updateQueue() { ClientHandler.addResponseListener(GetCheckUpQueueResponse.class, checkUpQueueListener); @@ -286,6 +292,7 @@ public class CheckUpPage extends JPanel { statusComboBox = new JComboBox<>(statusOptions); inputPanel.add(statusComboBox, gbc); table1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table1.getSelectionModel().addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { // Ensure final selection event int selectedRow = table1.getSelectedRow(); @@ -294,6 +301,7 @@ public class CheckUpPage extends JPanel { if(previousSelectedRow != selectedRow) { if(!saved) { JOptionPane.showMessageDialog(null, "Please save changes before selecting another patient"); + returnCell = true; table1.setRowSelectionInterval(previousSelectedRow, previousSelectedRow); return; } @@ -301,8 +309,12 @@ public class CheckUpPage extends JPanel { } // reset information + if (returnCell) { + returnCell = false; + return; + } medicinePrescription = new String[][]{}; - + servicePrescription = new String[][]{}; handleRowSelection(selectedRow); } @@ -330,8 +342,21 @@ public class CheckUpPage extends JPanel { JOptionPane.showMessageDialog(null, "Add action triggered"); break; case "service": - // Edit action - JOptionPane.showMessageDialog(null, "stethoscope action triggered"); + // If there is no user selected, show a warning message + if (checkupIdField.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, "Please select a patient from the queue"); + return; + } + // Open service dialog + if(serDialog == null) { + serDialog = new ServiceDialog(mainFrame); + previousSelectedRow = table1.getSelectedRow(); + } + serDialog.setVisible(true); + saved = false; + servicePrescription = serDialog.getServicePrescription(); + + log.info("Service prescription: {}", servicePrescription); break; case "save": { //Warning message @@ -352,15 +377,22 @@ public class CheckUpPage extends JPanel { return; } // Open medicine dialog - if(previousSelectedRow != table1.getSelectedRow()) { - dialog = new MedicineDialog(mainFrame); + if(medDialog == null) { + medDialog = new MedicineDialog(mainFrame); previousSelectedRow = table1.getSelectedRow(); } - dialog.setVisible(true); + medDialog.setVisible(true); saved = false; - medicinePrescription = dialog.getMedicinePrescription(); + medicinePrescription = medDialog.getMedicinePrescription(); log.info("Medicine prescription: {}", medicinePrescription); + + break; + case "printer": + // Print action + JOptionPane.showMessageDialog(null, "Print action triggered"); + log.info("Medicine prescription: {}", (Object) medicinePrescription); + log.info("Service prescription: {}", (Object) servicePrescription); break; default: throw new IllegalStateException("Unexpected value: " + name); diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java similarity index 93% rename from src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java rename to src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java index 78f9e9b..fc6006a 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/Demo.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/Demo.java @@ -1,4 +1,4 @@ -package BsK.client.ui.component.CheckUpPage.MedicineWindow; +package BsK.client.ui.component.CheckUpPage.MedicineDialog; import javax.swing.*; import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator; diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java similarity index 97% rename from src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java rename to src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java index 0affa11..587b72b 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineWindow/MedicineDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java @@ -1,21 +1,17 @@ -package BsK.client.ui.component.CheckUpPage.MedicineWindow; +package BsK.client.ui.component.CheckUpPage.MedicineDialog; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumnModel; -import javax.swing.table.TableRowSorter; import BsK.client.network.handler.ClientHandler; import BsK.client.network.handler.ResponseListener; -import BsK.common.packet.req.GetDoctorGeneralInfo; import BsK.common.packet.req.GetMedInfoRequest; import BsK.common.packet.res.GetMedInfoResponse; import BsK.common.util.network.NetworkUtil; -import BsK.server.network.util.UserUtil; import lombok.extern.slf4j.Slf4j; -import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,11 +21,9 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.HashMap; -import java.util.List; @Slf4j public class MedicineDialog extends JDialog { - private static final Logger log = LoggerFactory.getLogger(MedicineDialog.class); private JTextField medicineNameField; private JTextField medicineCompanyField; private JTextArea medicineDescriptionField; @@ -335,6 +329,7 @@ public class MedicineDialog extends JDialog { rowData[i] = tableModel.getValueAt(modelRow, i); } + rowData[4] = quantitySpinner.getValue(); rowData[7] = totalField.getText(); rowData[8] = noteField.getText(); selectedTableModel.addRow(rowData); @@ -387,6 +382,8 @@ public class MedicineDialog extends JDialog { quantityLeftField.setText(stock); UnitComboBox.setSelectedItem(unit); priceField.setText(price); + totalField.setText("0"); + noteField.setText(""); } public static void main(String[] args) { diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/EditableMedicalInvoice.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/EditableMedicalInvoice.java new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java new file mode 100644 index 0000000..582abde --- /dev/null +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicalInvoiceWithGUI.java @@ -0,0 +1,183 @@ +package BsK.client.ui.component.CheckUpPage.PrintDialog; + +import com.itextpdf.io.image.ImageData; +import com.itextpdf.io.image.ImageDataFactory; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.*; +import com.itextpdf.layout.element.Image; +import com.itextpdf.layout.property.UnitValue; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.rendering.PDFRenderer; + +import javax.print.*; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; + +public class MedicalInvoiceWithGUI { + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> new MedicalInvoiceWithGUI().createGUI()); + } + + private void createGUI() { + JFrame frame = new JFrame("Medical Invoice"); + frame.setSize(600, 600); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setLayout(new BorderLayout()); + + JPanel buttonPanel = new JPanel(new GridLayout(1, 3)); + JButton previewButton = new JButton("Preview PDF"); + JButton saveButton = new JButton("Save PDF"); + JButton printButton = new JButton("Print PDF"); + + buttonPanel.add(previewButton); + buttonPanel.add(saveButton); + buttonPanel.add(printButton); + + JLabel pdfViewer = new JLabel(); + JScrollPane scrollPane = new JScrollPane(pdfViewer); + frame.add(scrollPane, BorderLayout.CENTER); + frame.add(buttonPanel, BorderLayout.SOUTH); + + String pdfPath = "medical_invoice.pdf"; + + // Preview PDF Action + previewButton.addActionListener(e -> { + try { + generatePdf(pdfPath); + displayPdfInLabel(pdfPath, pdfViewer); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(frame, "Error displaying PDF: " + ex.getMessage()); + } + }); + + // Save PDF Action + saveButton.addActionListener(e -> { + try { + generatePdf(pdfPath); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle("Save PDF As"); + fileChooser.setSelectedFile(new File("medical_invoice.pdf")); + int userSelection = fileChooser.showSaveDialog(frame); + + if (userSelection == JFileChooser.APPROVE_OPTION) { + File fileToSave = fileChooser.getSelectedFile(); + File generatedFile = new File(pdfPath); + try (InputStream in = new FileInputStream(generatedFile); + OutputStream out = new FileOutputStream(fileToSave)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + } + JOptionPane.showMessageDialog(frame, "PDF saved: " + fileToSave.getAbsolutePath()); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(frame, "Error saving PDF: " + ex.getMessage()); + } + }); + + // Print PDF Action + printButton.addActionListener(e -> { + try { + generatePdf(pdfPath); + File pdfFile = new File(pdfPath); + printPdf(pdfFile); + JOptionPane.showMessageDialog(frame, "Printing triggered."); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(frame, "Error printing PDF: " + ex.getMessage()); + } + }); + + frame.setVisible(true); + } + + private void generatePdf(String pdfPath) throws Exception { + PdfWriter writer = new PdfWriter(pdfPath); + PdfDocument pdfDoc = new PdfDocument(writer); + Document document = new Document(pdfDoc); + + // Add logo + String logoPath = "/Users/lethanhdat/Documents/GitHub/ldS_BsK/src/main/java/BsK/client/ui/assets/icon/add.png"; // Path to your logo + ImageData imageData = ImageDataFactory.create(logoPath); + Image logo = new Image(imageData).scaleToFit(100, 100); + logo.setFixedPosition(50, 750); + document.add(logo); + + // Add clinic information + String clinicInfo = "Your Clinic Name\n123 Clinic Street\nCity, State, ZIP\nPhone: (123) 456-7890\nEmail: clinic@example.com"; + Paragraph clinicInfoParagraph = new Paragraph(clinicInfo).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT); + document.add(clinicInfoParagraph); + + // Add patient and doctor names + String patientDoctorInfo = "Patient: John Doe\nDoctor: Dr. Jane Smith"; + Paragraph patientDoctorParagraph = new Paragraph(patientDoctorInfo); + document.add(patientDoctorParagraph); + + // Add services and medicine table + Table table = new Table(UnitValue.createPercentArray(new float[]{4, 2, 2})) + .setWidth(UnitValue.createPercentValue(100)); + table.addHeaderCell("Service/Medicine"); + table.addHeaderCell("Quantity"); + table.addHeaderCell("Price"); + table.addCell("Consultation"); + table.addCell("1"); + table.addCell("$50"); + table.addCell("Aspirin"); + table.addCell("2"); + table.addCell("$10"); + document.add(table); + + // Add diagnosis and notes + String diagnosisNotes = "Diagnosis: Flu\nNotes: Rest and hydration recommended"; + Paragraph diagnosisNotesParagraph = new Paragraph(diagnosisNotes); + document.add(diagnosisNotesParagraph); + + // Add signature area + Paragraph signatureArea = new Paragraph("\n\n\nSignature: ________________________"); + document.add(signatureArea); + + document.close(); + } + + private void displayPdfInLabel(String pdfPath, JLabel label) throws IOException { + PDDocument document = PDDocument.load(new File(pdfPath)); + PDFRenderer renderer = new PDFRenderer(document); + + // Render the first page + BufferedImage pageImage = renderer.renderImageWithDPI(0, 100); // 100 DPI for reasonable quality + ImageIcon icon = new ImageIcon(pageImage); + label.setIcon(icon); + + document.close(); + } + + public static void printPdf(File pdfFile) { + try { + PrintService printService = PrintServiceLookup.lookupDefaultPrintService(); + if (printService != null) { + DocPrintJob printJob = printService.createPrintJob(); + Doc pdfDoc = new SimpleDoc(pdfFile.toURI().toURL().openStream(), + javax.print.DocFlavor.INPUT_STREAM.PDF, null); + PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet(); + printJob.print(pdfDoc, attributes); + System.out.println("PDF sent to the printer."); + } else { + System.out.println("No default print service found."); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java new file mode 100644 index 0000000..c2671a0 --- /dev/null +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/PrintDialog.java @@ -0,0 +1,6 @@ +package BsK.client.ui.component.CheckUpPage.PrintDialog; + + +public class PrintDialog { + +} diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java new file mode 100644 index 0000000..21295b1 --- /dev/null +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java @@ -0,0 +1,334 @@ +package BsK.client.ui.component.CheckUpPage.ServiceDialog; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; + +import BsK.client.network.handler.ClientHandler; +import BsK.client.network.handler.ResponseListener; +import BsK.common.packet.req.GetSerInfoRequest; +import BsK.common.packet.res.GetSerInfoResponse; +import BsK.common.util.network.NetworkUtil; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.HashMap; + +@Slf4j +public class ServiceDialog extends JDialog { + private JTextField serviceNameField; + private JSpinner quantitySpinner; + private JTextField priceField; + private JTextField totalField; + private JTextArea noteField; + private DefaultTableModel tableModel, selectedTableModel; + private String[] serviceColumns = {"ID", "Service Name", "Price"}; + private String[][] serviceData; + private final ResponseListener getSerInfoResponseListener = this::getSerInfoHandler; + private TableColumnModel columnModel; + private HashMap selectedService = new HashMap<>(); + private JTable serviceTable; + private JTable selectedTable; + + private String[][] servicePrescription; + + public String[][] getServicePrescription() { + return servicePrescription; + } + + void getSerInfoHandler(GetSerInfoResponse response) { + log.info("Received service data"); + serviceData = response.getSerInfo(); + tableModel.setDataVector(serviceData, serviceColumns); + + // resize column width + columnModel = serviceTable.getColumnModel(); + columnModel.getColumn(0).setPreferredWidth(10); + columnModel.getColumn(1).setPreferredWidth(200); + columnModel.getColumn(2).setPreferredWidth(50); + } + + void sendGetSerInfoRequest() { + log.info("Sending GetSerInfoRequest"); + NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetSerInfoRequest()); + } + + public ServiceDialog(Frame parent) { + super(parent, "Enter Service Details", true); + + // Set the size of the dialog + setSize(1100, 500); + setResizable(true); + + ClientHandler.addResponseListener(GetSerInfoResponse.class, getSerInfoResponseListener); + sendGetSerInfoRequest(); + + setLayout(new BorderLayout()); + + + JPanel inputPanel = new JPanel(); + inputPanel.setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + + + gbc.insets = new Insets(5, 5, 5, 5); // Padding between components + gbc.weightx = 1.0; // Components stretch horizontally + gbc.weighty = 0.0; // Allow minor vertical flexibility + gbc.fill = GridBagConstraints.HORIZONTAL; + + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; + gbc.gridy = 0; + + inputPanel.add(new JLabel("Service Name:"), gbc); + gbc.gridx = 1; + serviceNameField = new JTextField(15); + inputPanel.add(serviceNameField, gbc); + + // Listen for changes in the text event + tableModel = new DefaultTableModel(serviceData, serviceColumns) { + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + serviceTable = new JTable(tableModel); + serviceTable.setFont(new Font("Serif", Font.BOLD, 20)); + serviceTable.setRowHeight(30); + serviceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + JScrollPane scrollPane = new JScrollPane(serviceTable); + + + serviceTable.setPreferredScrollableViewportSize(new Dimension(625, 200)); + + + scrollPane.setPreferredSize(new Dimension(625, 200)); + + + serviceTable.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + SwingUtilities.invokeLater(() -> { + int selectedRow = serviceTable.getSelectedRow(); + if (selectedRow != -1) { + handleRowSelection(selectedRow); + } + }); + } + }); + + serviceNameField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + handleRowSelection(serviceTable.getSelectedRow()); + } + } + }); + + + serviceNameField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + findAndSelectRow(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + findAndSelectRow(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + findAndSelectRow(); + } + + private void findAndSelectRow() { + String searchText = serviceNameField.getText().trim(); + if (searchText.isEmpty()) { + // Clear selection if search text is empty + serviceTable.clearSelection(); + return; + } + + boolean found = false; + for (int row = 0; row < serviceTable.getRowCount(); row++) { + // Assuming the search is targeting the name column (column index 1) + String cellValue = serviceTable.getValueAt(row, 1).toString(); + if (cellValue.toLowerCase().contains(searchText.toLowerCase())) { + serviceTable.setRowSelectionInterval(row, row); + serviceTable.scrollRectToVisible(serviceTable.getCellRect(row, 1, true)); + found = true; + break; // Stop after selecting the first match + } + } + + if (!found) { + serviceTable.clearSelection(); // No matches found + } + } + }); + + + gbc.gridx = 0; + gbc.gridy++; + inputPanel.add(new JLabel("Quantity:"), gbc); + + gbc.gridx = 1; + // Create and set preferred size for the spinner + quantitySpinner = new JSpinner(); + quantitySpinner.setPreferredSize(new Dimension(100, 25)); // Adjust width and height as needed + inputPanel.add(quantitySpinner, gbc); + + + gbc.gridx = 0; + gbc.gridy++; + inputPanel.add(new JLabel("Price:"), gbc); + gbc.gridx = 1; + priceField = new JTextField(15); + inputPanel.add(priceField, gbc); + + gbc.gridx = 0; + gbc.gridy++; + inputPanel.add(new JLabel("Total:"), gbc); + gbc.gridx = 1; + totalField = new JTextField(15); + inputPanel.add(totalField, gbc); + + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.gridx = 0; + gbc.gridy++; + inputPanel.add(new JLabel("Note:"), gbc); + gbc.gridx = 1; + noteField = new JTextArea(2, 15); + inputPanel.add(noteField, gbc); + gbc.anchor = GridBagConstraints.WEST; + + quantitySpinner.addChangeListener(e -> { + int quantity = (int) quantitySpinner.getValue(); + if (quantity < 0) { + quantity = 0; + quantitySpinner.setValue(quantity); + } + + double price = Double.parseDouble(priceField.getText()); + totalField.setText(String.valueOf(quantity * price)); + }); + + + + // Set the split pane + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inputPanel, scrollPane); + splitPane.setResizeWeight(0.5); // Allocate more space to the inputPanel + // Wrap the splitPane in a JPanel to control height + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.add(splitPane, BorderLayout.CENTER); + + + // Create a table to display selected services + String[] columnNames = {"ID", "Service Name", "Quantity", "Single Price", "Total Price", "Note"}; + selectedTableModel = new DefaultTableModel(new String[][]{}, columnNames) { + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + + selectedTable = new JTable(selectedTableModel); + JScrollPane tableScrollPane = new JScrollPane(selectedTable); + + // Create a panel for add and remove buttons + JPanel buttonPanel = new JPanel(); + JButton addButton = new JButton("Add"); + JButton removeButton = new JButton("Remove"); + JButton submitButton = new JButton("Submit"); + buttonPanel.add(addButton); + buttonPanel.add(removeButton); + buttonPanel.add(submitButton); + + addButton.addActionListener(e -> { + int selectedRow = serviceTable.getSelectedRow(); + if (selectedRow != -1) { + int modelRow = serviceTable.convertRowIndexToModel(selectedRow); + if(selectedService.containsKey(tableModel.getValueAt(modelRow, 0).toString())) { + JOptionPane.showMessageDialog(this, "Service already added", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + selectedService.put((String) tableModel.getValueAt(modelRow, 0), true); + Object[] rowData = new Object[6]; + + rowData[0] = tableModel.getValueAt(modelRow, 0); + rowData[1] = tableModel.getValueAt(modelRow, 1); + rowData[2] = quantitySpinner.getValue(); + rowData[3] = priceField.getText(); + rowData[4] = totalField.getText(); + rowData[5] = noteField.getText(); + selectedTableModel.addRow(rowData); + log.info("Added service with id: {}", tableModel.getValueAt(modelRow, 0)); + } + }); + + removeButton.addActionListener(e -> { + int selectedRow = selectedTable.getSelectedRow(); + if (selectedRow != -1) { + String id = selectedTableModel.getValueAt(selectedRow, 0).toString(); + selectedService.remove(id); + log.info("Removed service with id: {}", id); + selectedTableModel.removeRow(selectedRow); + } + }); + + submitButton.addActionListener(e -> { + int rows = selectedTableModel.getRowCount(); + servicePrescription = new String[rows][6]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < 6; j++) { + servicePrescription[i][j] = selectedTableModel.getValueAt(i, j).toString(); + } + } + dispose(); + }); + + // Add components to the dialog + add(topPanel, BorderLayout.NORTH); + add(tableScrollPane, BorderLayout.CENTER); + add(buttonPanel, BorderLayout.SOUTH); + + setLocationRelativeTo(parent); + } + + private void handleRowSelection(int selectedRow) { + String id = (String) tableModel.getValueAt(selectedRow, 0); + String name = (String) tableModel.getValueAt(selectedRow, 1); + String price = (String) tableModel.getValueAt(selectedRow, 2); + + serviceNameField.setText(name); + quantitySpinner.setValue(0); + priceField.setText(price); + totalField.setText("0"); + noteField.setText(""); + } + + public static void main(String[] args) { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(400, 300); + frame.setVisible(true); + + JButton openDialogButton = new JButton("Open Service Dialog"); + openDialogButton.addActionListener(e -> { + ServiceDialog dialog = new ServiceDialog(frame); + dialog.setVisible(true); + }); + + frame.add(openDialogButton, BorderLayout.CENTER); + } +} diff --git a/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java b/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java new file mode 100644 index 0000000..dc3fb92 --- /dev/null +++ b/src/main/java/BsK/common/packet/req/GetSerInfoRequest.java @@ -0,0 +1,12 @@ +package BsK.common.packet.req; + +import BsK.common.packet.Packet; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +@AllArgsConstructor +public class GetSerInfoRequest implements Packet { +} diff --git a/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java b/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java new file mode 100644 index 0000000..5276232 --- /dev/null +++ b/src/main/java/BsK/common/packet/res/GetSerInfoResponse.java @@ -0,0 +1,13 @@ +package BsK.common.packet.res; + +import BsK.common.packet.Packet; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +@AllArgsConstructor +public class GetSerInfoResponse implements Packet { + private String[][] serInfo; +} diff --git a/src/main/java/BsK/server/network/handler/ServerHandler.java b/src/main/java/BsK/server/network/handler/ServerHandler.java index f5f36b3..df2ec9a 100644 --- a/src/main/java/BsK/server/network/handler/ServerHandler.java +++ b/src/main/java/BsK/server/network/handler/ServerHandler.java @@ -236,6 +236,40 @@ public class ServerHandler extends SimpleChannelInboundHandler resultList = new ArrayList<>(); + while (rs.next()) { + String serId = rs.getString("service_id"); + String serName = rs.getString("service_name"); + String serPrice = rs.getString("service_cost"); + + String result = String.join("|", serId, serName, serPrice); + resultList.add(result); + } + + String[] resultString = resultList.toArray(new String[0]); + String[][] resultArray = new String[resultString.length][]; + for (int i = 0; i < resultString.length; i++) { + resultArray[i] = resultString[i].split("\\|"); + } + + UserUtil.sendPacket(user.getSessionId(), new GetSerInfoResponse(resultArray)); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } } } diff --git a/src/main/resources/database/BSK.db b/src/main/resources/database/BSK.db index 450d809..929fa47 100644 Binary files a/src/main/resources/database/BSK.db and b/src/main/resources/database/BSK.db differ