zsh_root
2025-12-10 8d662de2fd262b3a485f16e197cb4d0ca2a61cdf
src/home/NetworkConfigPanel.java
@@ -1,304 +1,1087 @@
package home;
import jiexi.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.io.IOException;
import java.util.Vector;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class NetworkConfigPanel extends JPanel {
    // 基础设置面板组件
    private JComboBox<String> ipTypeComboBox;
    private JTextField staticIpField;
    private JTextField subnetMaskField;
    private JTextField gatewayField;
    private JTextField dnsServerField;
    private JTextField macAddressField;
    private JTextField timeoutRestartField;
    private JTextField httpServerPortField;
    private JTextField usernameField;
    private JTextField passwordField;
    private JTextField deviceNameField;
    // 选项复选框
    private JCheckBox indexCheckBox;
    private JCheckBox resetCheckBox;
    private JCheckBox linkCheckBox;
    private JCheckBox rfc2217CheckBox;
    private JCheckBox cacheClearCheckBox;
    private JCheckBox serialSettingsCheckBox;
    // 端口设置面板组件
    private JComboBox<String> workModeComboBox;
    private JTextField targetUrlField;
    private JTextField shortConnectionTimeField;
    private JComboBox<String> baudRateComboBox;
    private JTextField localPortField;
    private JTextField remotePortField;
    private JComboBox<String> tcpClientCountComboBox;
    private JCheckBox enableShortConnectionCheckBox;
    // 串口参数组件
    private JComboBox<String> parityComboBox;
    private JComboBox<String> dataBitsComboBox;
    private JComboBox<String> stopBitsComboBox;
    private static final long serialVersionUID = 1L;
    private MainFrame mainFrame;
    private JComboBox<String> protocolCombo;
    private JTextField addressField, portField;
    private JButton openBtn, searchBtn;
    private JLabel protocolLabel, addressLabel, portLabel;
    private JButton readBtn, searchBtn, saveBtn;
    private JTable deviceTable;
    private JPanel basicSettingsPanel, portSettingsPanel;
    // 新增:标签引用用于语言切换
    private JLabel deviceListLabel;
    
    // 保存所有参数行的标签引用,用于语言切换
    private Map<String, JLabel> parameterLabels = new HashMap<>();
    private JLabel optionsLabel;
    private JLabel parityDataStopLabel;
    // 在类变量区域添加
    private DeviceConfig currentDeviceConfig;
    public NetworkConfigPanel(MainFrame mainFrame) {
        this.mainFrame = mainFrame;
        initializeUI();
    }
    private void initializeUI() {
        setLayout(new BorderLayout());
        // 控制面板
        // 控制面板
        add(createControlPanel(), BorderLayout.NORTH);
        // 设备表格和配置面板
        // 设备表格和配置面板
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        splitPane.setLeftComponent(createDeviceTablePanel());
        splitPane.setRightComponent(createConfigPanel());
        splitPane.setDividerLocation(400);
        add(splitPane, BorderLayout.CENTER);
    }
    private JPanel createControlPanel() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        protocolLabel = new JLabel(getString("protocol.type"));
        panel.add(protocolLabel);
        protocolCombo = new JComboBox<>(new String[]{"UDP", "TCP"});
        protocolCombo.setPreferredSize(new Dimension(150, 25));
        panel.add(protocolCombo);
        addressLabel = new JLabel(getString("local.host.address"));
        panel.add(addressLabel);
        addressField = new JTextField();
        addressField.setPreferredSize(new Dimension(150, 25));
        panel.add(addressField);
        portLabel = new JLabel(getString("local.host.port"));
        panel.add(portLabel);
        portField = new JTextField();
        portField.setPreferredSize(new Dimension(150, 25));
        panel.add(portField);
        // 使用ButtonUtils获取统一样式的按钮
        openBtn = ButtonUtils.createBlueButton(getString("open"));
        searchBtn = ButtonUtils.createBlueButton(getString("search.devices"));
        panel.add(openBtn);
        readBtn = ButtonUtils.createBlueButton(getString("read.parameters"));
        saveBtn = ButtonUtils.createBlueButton(getString("save.parameters")); // 新增保存按钮
        // 添加按钮的点击事件监听器
        searchBtn.addActionListener(e -> searchDevices());
        readBtn.addActionListener(e -> readDevices());
        saveBtn.addActionListener(e -> saveDeviceConfig()); // 新增保存事件
        panel.add(searchBtn);
        panel.add(readBtn);
        panel.add(saveBtn); // 添加到面板
        return panel;
    }
    private void readDevices() {
        // 获取选中的设备
        int selectedRow = deviceTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this,
                    getString("please.select.device"),
                    getString("prompt"),
                    JOptionPane.WARNING_MESSAGE);
            return;
        }
        // 检查是否只选中了一个设备
        int[] selectedRows = deviceTable.getSelectedRows();
        if (selectedRows.length > 1) {
            JOptionPane.showMessageDialog(this,
                    getString("select.one.device"),
                    getString("prompt"),
                    JOptionPane.WARNING_MESSAGE);
            return;
        }
        // 获取选中设备的IP和MAC地址
        String deviceIp = (String) deviceTable.getValueAt(selectedRow, 1); // 第二列是IP地址
        String deviceMac = (String) deviceTable.getValueAt(selectedRow, 3); // 第四列是MAC地址
        // 在新线程中执行UDP读取操作
        new Thread(() -> {
            DatagramSocket socket = null;
            try {
                // 创建UDP Socket
                socket = new DatagramSocket();
                socket.setSoTimeout(5000); // 设置5秒超时
                // 准备读取配置的数据
                byte[] sendData = DellS2.reads2peizhi((byte) 0x03, deviceMac);
                // 创建目标地址:选中设备的IP,端口1500
                InetAddress deviceAddress = InetAddress.getByName(deviceIp);
                int port = 1500;
                // 创建数据包
                DatagramPacket packet = new DatagramPacket(sendData, sendData.length, deviceAddress, port);
                // 发送读取请求
                socket.send(packet);
                // 准备接收响应
                byte[] receiveData = new byte[1024];
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                // 接收响应
                socket.receive(receivePacket);
                // 处理响应数据
                processReadResponse(receivePacket, deviceIp, deviceMac);
            } catch (SocketTimeoutException e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this,
                            getString("read.timeout"),
                            getString("error"),
                            JOptionPane.ERROR_MESSAGE);
                });
            } catch (UnknownHostException e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this,
                            getString("invalid.ip.address") + ": " + deviceIp,
                            getString("error"),
                            JOptionPane.ERROR_MESSAGE);
                });
            } catch (IOException e) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this,
                            getString("read.device.error") + ": " + e.getMessage(),
                            getString("error"),
                            JOptionPane.ERROR_MESSAGE);
                });
                e.printStackTrace();
            } finally {
                // 关闭socket
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            }
        }).start();
    }
    /**
     * 处理读取配置的响应数据
     */
    private void processReadResponse(DatagramPacket packet, String deviceIp, String deviceMac) {
        // 获取响应数据
        byte[] responseData = packet.getData();
        int dataLength = packet.getLength();
        // 将字节数据转换为十六进制字符串
        String hexData = bytesToHex(responseData, dataLength);
        // 打印到控制台
        System.out.println(hexData);
        DeviceConfig deviceConfig = DeviceConfigParser.parseDeviceConfig(hexData);
        // 保存当前设备配置
        this.currentDeviceConfig = deviceConfig;
        // 将解析的配置数据应用到UI组件
        updateUIWithDeviceConfig(deviceConfig);
        // 在UI线程中显示成功消息
        SwingUtilities.invokeLater(() -> {
            JOptionPane.showMessageDialog(this,
                    getString("read.success") + "\nIP: " + deviceIp + "\nMAC: " + deviceMac,
                    getString("success"),
                    JOptionPane.INFORMATION_MESSAGE);
        });
    }
    /**
     * 保存设备配置 - 将UI配置赋值回DeviceConfig对象并通过UDP广播发送
     */
    private void saveDeviceConfig() {
        if (currentDeviceConfig == null) {
            JOptionPane.showMessageDialog(this,
                    getString("read.parameters.first"),
                    getString("prompt"),
                    JOptionPane.WARNING_MESSAGE);
            return;
        }
        try {
            // 从UI更新基础设置到DeviceConfig
            updateDeviceConfigFromBasicSettings();
            // 从UI更新端口设置到DeviceConfig
            updateDeviceConfigFromPortSettings();
            String mac = currentDeviceConfig.getMacAddress().replaceAll(":", "");
            byte[] bytes = DellS2.alert_s2(currentDeviceConfig.getStaticIp(), currentDeviceConfig.getGatewayIp(),
                    currentDeviceConfig.getSubnetMask(), currentDeviceConfig.getModuleName(), mac);
            byte[] bytes1 = DellS2.alert_s2_chuankou(currentDeviceConfig.getTargetUrl(), mac,
                    "0" + currentDeviceConfig.getWorkMode(), currentDeviceConfig.getRemotePort() + "",
                    currentDeviceConfig.getBaudRate() + "");
            byte[] bytes2 = DellS2.reads2peizhi((byte) 0x02, mac);
            // 在新线程中执行UDP发送操作
            new Thread(() -> {
                DatagramSocket socket = null;
                try {
                    // 创建UDP Socket
                    socket = new DatagramSocket();
                    socket.setBroadcast(true);
                    // 创建广播地址:255.255.255.255,端口1500
                    InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
                    int port = 1500;
                    // 发送第一个数据包 (bytes)
                    if (bytes != null && bytes.length > 0) {
                        DatagramPacket packet1 = new DatagramPacket(bytes, bytes.length, broadcastAddress, port);
                        socket.send(packet1);
                    }
                    if (bytes1 != null && bytes1.length > 0) {
                        DatagramPacket packet2 = new DatagramPacket(bytes1, bytes1.length, broadcastAddress, port);
                        socket.send(packet2);
                    }
                    if (bytes2 != null && bytes2.length > 0) {
                        DatagramPacket packet3 = new DatagramPacket(bytes2, bytes2.length, broadcastAddress, port);
                        socket.send(packet3);
                    }
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("save.success"),
                                getString("success"),
                                JOptionPane.INFORMATION_MESSAGE);
                    });
                } catch (SocketException e) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("udp.socket.failed") + ": " + e.getMessage(),
                                getString("error"),
                                JOptionPane.ERROR_MESSAGE);
                    });
                } catch (UnknownHostException e) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("invalid.broadcast.address"),
                                getString("error"),
                                JOptionPane.ERROR_MESSAGE);
                    });
                } catch (IOException e) {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("send.udp.failed") + ": " + e.getMessage(),
                                getString("error"),
                                JOptionPane.ERROR_MESSAGE);
                    });
                } finally {
                    // 关闭socket
                    if (socket != null && !socket.isClosed()) {
                        socket.close();
                    }
                }
            }).start();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this,
                    getString("save.config.error") + ": " + e.getMessage(),
                    getString("error"),
                    JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
        }
    }
    /**
     * 从基础设置UI更新DeviceConfig
     */
    private void updateDeviceConfigFromBasicSettings() {
        // IP地址类型
        currentDeviceConfig.setIpType(ipTypeComboBox.getSelectedIndex());
        // 网络配置
        currentDeviceConfig.setStaticIp(staticIpField.getText().trim());
        currentDeviceConfig.setSubnetMask(subnetMaskField.getText().trim());
        currentDeviceConfig.setGatewayIp(gatewayField.getText().trim());
        currentDeviceConfig.setDnsServer(dnsServerField.getText().trim());
        currentDeviceConfig.setMacAddress(macAddressField.getText().trim());
        // 设备信息
        currentDeviceConfig.setModuleName(deviceNameField.getText().trim());
        currentDeviceConfig.setUsername(usernameField.getText().trim());
        currentDeviceConfig.setPassword(passwordField.getText().trim());
        // 数字字段需要转换
        try {
            if (!httpServerPortField.getText().trim().isEmpty()) {
                currentDeviceConfig.setHttpServerPort(Integer.parseInt(httpServerPortField.getText().trim()));
            }
            if (!timeoutRestartField.getText().trim().isEmpty()) {
                currentDeviceConfig.setTimeoutRestart(Integer.parseInt(timeoutRestartField.getText().trim()));
            }
        } catch (NumberFormatException e) {
            throw new RuntimeException(getString("port.timeout.format.error"), e);
        }
        // 功能选项
        currentDeviceConfig.setIndex(indexCheckBox.isSelected());
        currentDeviceConfig.setReset(resetCheckBox.isSelected());
        currentDeviceConfig.setLink(linkCheckBox.isSelected());
        currentDeviceConfig.setRfc2217(rfc2217CheckBox.isSelected());
        currentDeviceConfig.setCacheClear(cacheClearCheckBox.isSelected());
    }
    /**
     * 从端口设置UI更新DeviceConfig
     */
    private void updateDeviceConfigFromPortSettings() {
        // 串口配置
        try {
            if (baudRateComboBox.getSelectedItem() != null) {
                currentDeviceConfig.setBaudRate(Integer.parseInt(baudRateComboBox.getSelectedItem().toString()));
            }
            // 数据位、校验位、停止位需要根据描述反向映射到数值
            currentDeviceConfig.setDataBitsDesc(dataBitsComboBox.getSelectedItem().toString());
            currentDeviceConfig.setParityDesc(parityComboBox.getSelectedItem().toString());
            currentDeviceConfig.setStopBitsDesc(stopBitsComboBox.getSelectedItem().toString());
        } catch (NumberFormatException e) {
            throw new RuntimeException(getString("baudrate.format.error"), e);
        }
        // 通信配置
        currentDeviceConfig.setWorkModeDesc(workModeComboBox.getSelectedItem().toString());
        currentDeviceConfig.setTargetUrl(targetUrlField.getText().trim());
        // 数字字段需要转换
        try {
            if (!shortConnectionTimeField.getText().trim().isEmpty()) {
                currentDeviceConfig.setShortConnectionTime(Integer.parseInt(shortConnectionTimeField.getText().trim()));
            }
            if (!localPortField.getText().trim().isEmpty()) {
                currentDeviceConfig.setLocalPort(Integer.parseInt(localPortField.getText().trim()));
            }
            if (!remotePortField.getText().trim().isEmpty()) {
                currentDeviceConfig.setRemotePort(Integer.parseInt(remotePortField.getText().trim()));
            }
            if (tcpClientCountComboBox.getSelectedItem() != null) {
                currentDeviceConfig.setTcpClientCount(Integer.parseInt(tcpClientCountComboBox.getSelectedItem().toString()));
            }
        } catch (NumberFormatException e) {
            throw new RuntimeException(getString("port.time.format.error"), e);
        }
        // 连接类型
        currentDeviceConfig.setConnectionType(enableShortConnectionCheckBox.isSelected() ? 0 : 1);
    }
    /**
     * 将DeviceConfig配置数据应用到UI组件
     */
    public void updateUIWithDeviceConfig(DeviceConfig config) {
        if (config == null) return;
        // 在EDT线程中更新UI
        SwingUtilities.invokeLater(() -> {
            try {
                // 更新基础设置面板
                updateBasicSettings(config);
                // 更新端口设置面板
                updatePortSettings(config);
            } catch (Exception e) {
                System.err.println(getString("update.ui.error") + ": " + e.getMessage());
                e.printStackTrace();
            }
        });
    }
    private void updateBasicSettings(DeviceConfig config) {
        // IP地址类型
        if (ipTypeComboBox != null) {
            ipTypeComboBox.setSelectedIndex(config.getIpType());
        }
        // 网络配置
        setTextFieldText(staticIpField, config.getStaticIp());
        setTextFieldText(subnetMaskField, config.getSubnetMask());
        setTextFieldText(gatewayField, config.getGatewayIp());
        setTextFieldText(dnsServerField, config.getDnsServer());
        setTextFieldText(macAddressField, config.getMacAddress());
        // 设备信息
        setTextFieldText(deviceNameField, config.getModuleName());
        setTextFieldText(usernameField, config.getUsername());
        setTextFieldText(passwordField, config.getPassword());
        setTextFieldText(httpServerPortField, String.valueOf(config.getHttpServerPort()));
        setTextFieldText(timeoutRestartField, String.valueOf(config.getTimeoutRestart()));
        // 功能选项
        setCheckBoxSelected(indexCheckBox, config.isIndex());
        setCheckBoxSelected(resetCheckBox, config.isReset());
        setCheckBoxSelected(linkCheckBox, config.isLink());
        setCheckBoxSelected(rfc2217CheckBox, config.isRfc2217());
        setCheckBoxSelected(cacheClearCheckBox, config.isCacheClear());
    }
    private void updatePortSettings(DeviceConfig config) {
        // 串口配置
        setComboBoxSelectedItem(baudRateComboBox, String.valueOf(config.getBaudRate()));
        setComboBoxSelectedItem(dataBitsComboBox, config.getDataBitsDesc());
        setComboBoxSelectedItem(parityComboBox, config.getParityDesc());
        setComboBoxSelectedItem(stopBitsComboBox, config.getStopBitsDesc());
        // 通信配置
        setComboBoxSelectedItem(workModeComboBox, config.getWorkModeDesc());
        setTextFieldText(targetUrlField, config.getTargetUrl());
        setTextFieldText(shortConnectionTimeField, String.valueOf(config.getShortConnectionTime()));
        setTextFieldText(localPortField, String.valueOf(config.getLocalPort()));
        setTextFieldText(remotePortField, String.valueOf(config.getRemotePort()));
        setComboBoxSelectedItem(tcpClientCountComboBox, String.valueOf(config.getTcpClientCount()));
        // 连接类型
        setCheckBoxSelected(enableShortConnectionCheckBox, config.getConnectionType() == 0);
    }
    // 辅助方法
    private void setTextFieldText(JTextField field, String text) {
        if (field != null && text != null) {
            field.setText(text);
        }
    }
    private void setCheckBoxSelected(JCheckBox checkBox, boolean selected) {
        if (checkBox != null) {
            checkBox.setSelected(selected);
        }
    }
    private void setComboBoxSelectedItem(JComboBox<String> comboBox, String item) {
        if (comboBox != null && item != null) {
            comboBox.setSelectedItem(item);
        }
    }
    /**
     * 搜索设备 - 发送UDP广播数据并监听返回
     */
    private void searchDevices() {
        new Thread(() -> {
            DatagramSocket socket = null;
            try {
                // 创建UDP Socket
                socket = new DatagramSocket();
                socket.setBroadcast(true);
                // 设置接收超时时间为5秒
                socket.setSoTimeout(5000);
                // 准备要发送的数据:FF 01 01 02 (十六进制字节)
                byte[] sendData = DellS2.serch();
                // 创建广播地址:255.255.255.255,端口1500
                InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
                int port = 1500;
                DellS2.getRow().removeAllElements();
                prepareSearch();
                // 创建数据包
                DatagramPacket packet = new DatagramPacket(sendData, sendData.length, broadcastAddress, port);
                // 发送数据包
                socket.send(packet);
                // 监听设备响应
                listenForDeviceResponses(socket);
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                // 如果是超时异常,属于正常情况
                if (e instanceof SocketTimeoutException) {
                    System.out.println(getString("listen.timeout"));
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("search.complete.timeout"),
                                getString("search.complete"),
                                JOptionPane.INFORMATION_MESSAGE);
                    });
                } else {
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(this,
                                getString("send.receive.udp.failed") + ": " + e.getMessage(),
                                getString("error"),
                                JOptionPane.ERROR_MESSAGE);
                    });
                    e.printStackTrace();
                }
            } finally {
                // 关闭socket
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            }
        }).start();
    }
    /**
     * 监听设备响应
     */
    private void listenForDeviceResponses(DatagramSocket socket) {
        try {
            int responseCount = 0;
            long startTime = System.currentTimeMillis();
            long timeout = 5000; // 5秒超时
            // 持续监听直到超时
            while (System.currentTimeMillis() - startTime < timeout) {
                try {
                    // 准备接收缓冲区
                    byte[] receiveData = new byte[1024];
                    DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                    // 设置剩余超时时间
                    long remainingTime = timeout - (System.currentTimeMillis() - startTime);
                    if (remainingTime <= 0) break;
                    socket.setSoTimeout((int) remainingTime);
                    // 接收数据
                    socket.receive(receivePacket);
                    responseCount++;
                    // 处理接收到的数据
                    processDeviceResponse(receivePacket, responseCount);
                } catch (SocketTimeoutException e) {
                    // 超时继续循环,检查总超时
                    continue;
                }
            }
            System.out.println(getString("search.complete.responses") + " " + responseCount + " " + getString("devices.found"));
        } catch (IOException e) {
            System.err.println(getString("listen.device.error") + ": " + e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 处理设备响应数据
     */
    private void processDeviceResponse(DatagramPacket packet, int responseNumber) {
        // 获取响应数据
        byte[] responseData = packet.getData();
        int dataLength = packet.getLength();
        // 将字节数据转换为十六进制字符串
        String hexData = bytesToHex(responseData, dataLength);
        DellS2.serch_fanhui(hexData);
        // 在UI线程中更新设备表格
        SwingUtilities.invokeLater(() -> {
            Vector<S2data> row = DellS2.getRow();
            for (S2data s2data : row) {
                addDeviceToTable(s2data);
            }
        });
    }
    /**
     * 将字节数组转换为十六进制字符串
     */
    private String bytesToHex(byte[] bytes, int length) {
        StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex.toUpperCase());
        }
        return hexString.toString();
    }
    private JPanel createDeviceTablePanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder(getString("device.list")));
        deviceListLabel = new JLabel(getString("device.list"));
        panel.setBorder(BorderFactory.createTitledBorder(deviceListLabel.getText()));
        String[] columnNames = {
            getString("select"),
            getString("device.ip"),
            getString("device.name"),
            getString("mac.address"),
            getString("version")
                getString("select"),
                getString("device.ip"),
                getString("device.name"),
                getString("mac.address"),
                getString("version")
        };
        Object[][] data = {}; // 空数据,实际使用时动态填充
        deviceTable = new JTable(data, columnNames);
        // 显式使用 DefaultTableModel
        javax.swing.table.DefaultTableModel model = new javax.swing.table.DefaultTableModel(columnNames, 0) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                // 第一列是Boolean类型(选择框)
                if (columnIndex == 0) {
                    return Boolean.class;
                }
                return String.class;
            }
            @Override
            public boolean isCellEditable(int row, int column) {
                // 只有第一列(选择框)可编辑
                return column == 0;
            }
        };
        deviceTable = new JTable(model);
        // 设置选择模式为单选
        deviceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        // 添加选择监听器,确保只能选择一个设备
        deviceTable.getSelectionModel().addListSelectionListener(e -> {
            if (!e.getValueIsAdjusting()) {
                int selectedRow = deviceTable.getSelectedRow();
                if (selectedRow != -1) {
                    // 取消其他行的选择框
                    for (int i = 0; i < deviceTable.getRowCount(); i++) {
                        if (i != selectedRow) {
                            deviceTable.setValueAt(Boolean.FALSE, i, 0);
                        }
                    }
                    // 设置当前行的选择框为选中状态
                    deviceTable.setValueAt(Boolean.TRUE, selectedRow, 0);
                }
            }
        });
        JScrollPane scrollPane = new JScrollPane(deviceTable);
        panel.add(scrollPane, BorderLayout.CENTER);
        return panel;
    }
    /**
     * 清空设备表格
     */
    public void clearDeviceTable() {
        // 安全地获取模型
        if (deviceTable.getModel() instanceof javax.swing.table.DefaultTableModel) {
            javax.swing.table.DefaultTableModel model = (javax.swing.table.DefaultTableModel) deviceTable.getModel();
            model.setRowCount(0);
            System.out.println(getString("device.table.cleared"));
        } else {
            // 如果不是DefaultTableModel,使用其他方式清空
            System.err.println(getString("table.model.error"));
        }
    }
    /**
     * 添加设备到表格
     */
    private void addDeviceToTable(S2data deviceInfo) {
        // 安全地获取模型
        if (deviceTable.getModel() instanceof javax.swing.table.DefaultTableModel) {
            javax.swing.table.DefaultTableModel model = (javax.swing.table.DefaultTableModel) deviceTable.getModel();
            // 添加新设备到表格
            Object[] rowData = {
                    Boolean.FALSE,           // 选择框
                    deviceInfo.getIp(),  // 设备IP
                    deviceInfo.getName(),    // 设备名称
                    deviceInfo.getMac(),     // MAC地址
                    deviceInfo.getVersion()  // 版本
            };
            model.addRow(rowData);
        } else {
            System.err.println(getString("table.model.error"));
        }
    }
    private JPanel createConfigPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        // 创建包含基础设置和端口设置的滚动面板
        // 创建包含基础设置和端口设置的滚动面板
        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
        // 添加顶部间距
        // 添加顶部间距
        contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
        // 基础设置
        // 基础设置
        basicSettingsPanel = createBasicSettingsPanel();
        contentPanel.add(basicSettingsPanel);
        contentPanel.add(Box.createVerticalStrut(10));
        // 端口设置
        // 端口设置
        portSettingsPanel = createPortSettingsPanel();
        contentPanel.add(portSettingsPanel);
        // 将内容面板放入滚动面板
        // 将内容面板放入滚动面板
        JScrollPane scrollPane = new JScrollPane(contentPanel);
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        JPanel wrapperPanel = new JPanel(new BorderLayout());
        wrapperPanel.add(scrollPane, BorderLayout.CENTER);
        return wrapperPanel;
    }
    private JPanel createBasicSettingsPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBorder(BorderFactory.createTitledBorder(getString("basic.settings")));
        // 第一行
        panel.add(createParameterRow("ip.address.type", createComboBox(new String[]{getString("static.ip")}, 150, 25), true));
        // 第二行
        panel.add(createParameterRow("module.static.ip", createTextField("", 150, 25), true));
        // 第三行
        panel.add(createParameterRow("subnet.mask", createTextField("", 150, 25), true));
        // 第四行
        panel.add(createParameterRow("gateway", createTextField("", 150, 25), true));
        // 第五行
        panel.add(createParameterRow("dns.address", createTextField("", 150, 25), false));
        // 第六行
        panel.add(createParameterRow("user.mac.address", createTextField("", 150, 25), false));
        // 第七行
        panel.add(createParameterRow("timeout.restart", createTextField("", 150, 25), false));
        // 第八行
        panel.add(createParameterRow("http.service.port", createTextField("", 150, 25), false));
        // 第九行
        panel.add(createParameterRow("username", createTextField("", 150, 25), false));
        // 第十行
        panel.add(createParameterRow("password", createTextField("", 150, 25), false));
        // 第十一行
        panel.add(createParameterRow("device.name", createTextField("", 150, 25), false));
        // 第十二行 - 选项复选框(第一行)
        // 第一行 - IP地址类型
        ipTypeComboBox = createComboBox(new String[]{getString("static.ip")}, 150, 25);
        panel.add(createParameterRow("ip.address.type", ipTypeComboBox, true));
        // 第二行 - 模块静态IP
        staticIpField = createTextField("", 150, 25);
        panel.add(createParameterRow("module.static.ip", staticIpField, true));
        // 第三行 - 子网掩码
        subnetMaskField = createTextField("", 150, 25);
        panel.add(createParameterRow("subnet.mask", subnetMaskField, true));
        // 第四行 - 网关
        gatewayField = createTextField("", 150, 25);
        panel.add(createParameterRow("gateway", gatewayField, true));
        // 第五行 - DNS地址
        dnsServerField = createTextField("", 150, 25);
        panel.add(createParameterRow("dns.address", dnsServerField, false));
        // 第六行 - 用户MAC地址
        macAddressField = createTextField("", 150, 25);
        panel.add(createParameterRow("user.mac.address", macAddressField, false));
        // 第七行 - 超时重启时间
        timeoutRestartField = createTextField("", 150, 25);
        panel.add(createParameterRow("timeout.restart", timeoutRestartField, false));
        // 第八行 - HTTP服务端口
        httpServerPortField = createTextField("", 150, 25);
        panel.add(createParameterRow("http.service.port", httpServerPortField, false));
        // 第九行 - 用户名
        usernameField = createTextField("", 150, 25);
        panel.add(createParameterRow("username", usernameField, false));
        // 第十行 - 密码
        passwordField = createTextField("", 150, 25);
        panel.add(createParameterRow("password", passwordField, false));
        // 第十一行 - 设备名称
        deviceNameField = createTextField("", 150, 25);
        panel.add(createParameterRow("device.name", deviceNameField, false));
        // 第十二行 - 选项复选框(第一行)
        JPanel optionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        optionPanel.add(new JLabel(getString("options") + ":"));
        optionsLabel = new JLabel(getString("options") + ":");
        optionPanel.add(optionsLabel);
        JPanel checkPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        checkPanel.add(new JCheckBox("Index"));
        checkPanel.add(new JCheckBox("Reset"));
        checkPanel.add(new JCheckBox("Link"));
        checkPanel.add(new JCheckBox("RFC2217"));
        indexCheckBox = new JCheckBox(getString("option.index"));
        resetCheckBox = new JCheckBox(getString("option.reset"));
        linkCheckBox = new JCheckBox(getString("option.link"));
        rfc2217CheckBox = new JCheckBox(getString("option.rfc2217"));
        checkPanel.add(indexCheckBox);
        checkPanel.add(resetCheckBox);
        checkPanel.add(linkCheckBox);
        checkPanel.add(rfc2217CheckBox);
        optionPanel.add(checkPanel);
        optionPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.add(optionPanel);
        // 第十三行 - 选项复选框(第二行)
        // 第十三行 - 选项复选框(第二行)
        JPanel optionPanel2 = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        // 添加空标签保持对齐
        optionPanel2.add(new JLabel(" "));
        JPanel checkPanel2 = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        checkPanel2.add(new JCheckBox(getString("clear.cache")));
        checkPanel2.add(new JCheckBox(getString("serial.settings")));
        cacheClearCheckBox = new JCheckBox(getString("clear.cache"));
        serialSettingsCheckBox = new JCheckBox(getString("serial.settings"));
        checkPanel2.add(cacheClearCheckBox);
        checkPanel2.add(serialSettingsCheckBox);
        optionPanel2.add(checkPanel2);
        optionPanel2.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.add(optionPanel2);
        return panel;
    }
    private JPanel createPortSettingsPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBorder(BorderFactory.createTitledBorder(getString("port.settings")));
        // 第一行
        panel.add(createParameterRow("module.work.mode", createComboBox(new String[]{"UDP Client", "TCP Client", "TCP Server"}, 150, 25), false));
        // 第二行
        panel.add(createParameterRow("target.ip.domain", createTextField("", 150, 25), false));
        // 第三行
        panel.add(createParameterRow("short.connection.time", createTextField("", 150, 25), false));
        // 第四行
        panel.add(createParameterRow("serial.baud.rate", createComboBoxWithSelection(new String[]{"9600", "19200", "38400", "115200", "921600"}, "115200", 150, 25), false));
        // 第五行
        panel.add(createParameterRow("local.port", createTextField("", 150, 25), false));
        // 第六行
        panel.add(createParameterRow("remote.port", createTextField("", 150, 25), false));
        // 第七行
        panel.add(createParameterRow("tcp.server.connections", createComboBox(new String[]{"4", "3", "2", "1"}, 150, 25), false));
        // 第八行 - 开启短连接复选框
        // 第一行 - 模块工作模式
        workModeComboBox = createComboBox(new String[]{
            getString("work.mode.udp.client"),
            getString("work.mode.tcp.client"),
            getString("work.mode.tcp.server")
        }, 150, 25);
        panel.add(createParameterRow("module.work.mode", workModeComboBox, false));
        // 第二行 - 目标IP/域名
        targetUrlField = createTextField("", 150, 25);
        panel.add(createParameterRow("target.ip.domain", targetUrlField, false));
        // 第三行 - 短连接时间
        shortConnectionTimeField = createTextField("", 150, 25);
        panel.add(createParameterRow("short.connection.time", shortConnectionTimeField, false));
        // 第四行 - 串口波特率
        baudRateComboBox = createComboBoxWithSelection(new String[]{"9600", "19200", "38400", "115200", "921600"}, "115200", 150, 25);
        panel.add(createParameterRow("serial.baud.rate", baudRateComboBox, false));
        // 第五行 - 本地端口
        localPortField = createTextField("", 150, 25);
        panel.add(createParameterRow("local.port", localPortField, false));
        // 第六行 - 远程端口
        remotePortField = createTextField("", 150, 25);
        panel.add(createParameterRow("remote.port", remotePortField, false));
        // 第七行 - TCP Server连接数
        tcpClientCountComboBox = createComboBox(new String[]{"4", "3", "2", "1"}, 150, 25);
        panel.add(createParameterRow("tcp.server.connections", tcpClientCountComboBox, false));
        // 第八行 - 开启短连接复选框
        JPanel shortConnPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        shortConnPanel.add(new JLabel(" ")); // 空标签保持对齐
        shortConnPanel.add(new JLabel(" "));
        JPanel shortConnSubPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        shortConnSubPanel.add(new JCheckBox(getString("enable.short.connection")));
        enableShortConnectionCheckBox = new JCheckBox(getString("enable.short.connection"));
        shortConnSubPanel.add(enableShortConnectionCheckBox);
        shortConnPanel.add(shortConnSubPanel);
        shortConnPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.add(shortConnPanel);
        // 第九行 - 校验/数据/停止
        // 第九行 - 校验/数据/停止
        JPanel parityPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        parityPanel.add(new JLabel(getString("parity.data.stop") + ":"));
        parityDataStopLabel = new JLabel(getString("parity.data.stop") + ":");
        parityPanel.add(parityDataStopLabel);
        JPanel paritySubPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        paritySubPanel.add(createComboBox(new String[]{"NONE"}, 80, 25));
        paritySubPanel.add(createComboBox(new String[]{"8"}, 60, 25));
        paritySubPanel.add(createComboBox(new String[]{"1"}, 60, 25));
        parityComboBox = createComboBox(new String[]{getString("parity.none")}, 80, 25);
        dataBitsComboBox = createComboBox(new String[]{"8"}, 60, 25);
        stopBitsComboBox = createComboBox(new String[]{"1"}, 60, 25);
        paritySubPanel.add(parityComboBox);
        paritySubPanel.add(dataBitsComboBox);
        paritySubPanel.add(stopBitsComboBox);
        parityPanel.add(paritySubPanel);
        parityPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.add(parityPanel);
        // 第十行 - 保存参数按钮
        JPanel savePanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        savePanel.add(ButtonUtils.createBlueButton(getString("save.parameters")));
        savePanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.add(savePanel);
        return panel;
    }
    // 创建参数行的辅助方法,参考BaseStationPanel的布局
    // 创建参数行的辅助方法,参考BaseStationPanel的布局
    private JPanel createParameterRow(String paramKey, JComponent component, boolean withStar) {
        JPanel paramPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        String labelText = getString(paramKey);
        if (withStar) {
            labelText += " ★";
            labelText += " ★";
        }
        JLabel label = new JLabel(labelText);
        label.setPreferredSize(new Dimension(140, 25));
        
        // 保存标签引用,用于语言切换
        parameterLabels.put(paramKey, label);
        paramPanel.add(label);
        paramPanel.add(component);
        // 设置固定高度
        // 设置固定高度
        paramPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        return paramPanel;
    }
    // 创建文本框的辅助方法
    // 创建文本框的辅助方法
    private JTextField createTextField(String text, int width, int height) {
        JTextField textField = new JTextField(text);
        textField.setPreferredSize(new Dimension(width, height));
        return textField;
    }
    // 创建下拉框的辅助方法
    // 创建下拉框的辅助方法
    private JComboBox<String> createComboBox(String[] items, int width, int height) {
        JComboBox<String> comboBox = new JComboBox<>(items);
        comboBox.setPreferredSize(new Dimension(width, height));
        return comboBox;
    }
    // 创建带默认选择的下拉框
    // 创建带默认选择的下拉框
    private JComboBox<String> createComboBoxWithSelection(String[] items, String selected, int width, int height) {
        JComboBox<String> comboBox = createComboBox(items, width, height);
        comboBox.setSelectedItem(selected);
        return comboBox;
    }
    public void updateLanguage() {
        // 更新控制面板文本
        protocolLabel.setText(getString("protocol.type"));
        addressLabel.setText(getString("local.host.address"));
        portLabel.setText(getString("local.host.port"));
        openBtn.setText(getString("open"));
        // 更新控制面板按钮文本
        searchBtn.setText(getString("search.devices"));
        readBtn.setText(getString("read.parameters"));
        saveBtn.setText(getString("save.parameters"));
        // 更新设备表格标题
        if (deviceListLabel != null) {
            deviceListLabel.setText(getString("device.list"));
            // 更新表格边框标题
            if (deviceTable != null && deviceTable.getParent() != null &&
                deviceTable.getParent().getParent() instanceof JPanel) {
                JPanel tablePanel = (JPanel) deviceTable.getParent().getParent();
                tablePanel.setBorder(BorderFactory.createTitledBorder(getString("device.list")));
            }
        }
        // 更新设置面板边框标题
        if (basicSettingsPanel != null) {
            basicSettingsPanel.setBorder(BorderFactory.createTitledBorder(getString("basic.settings")));
        }
        if (portSettingsPanel != null) {
            portSettingsPanel.setBorder(BorderFactory.createTitledBorder(getString("port.settings")));
        }
        // 更新所有参数行的标签文本
        updateParameterRowLabels();
        
        // 更新设备表格标题
        if (deviceTable != null) {
            // 更新表格标题
        // 更新其他独立标签
        if (optionsLabel != null) {
            optionsLabel.setText(getString("options") + ":");
        }
        if (parityDataStopLabel != null) {
            parityDataStopLabel.setText(getString("parity.data.stop") + ":");
        }
        // 更新复选框文本
        if (indexCheckBox != null) {
            indexCheckBox.setText(getString("option.index"));
        }
        if (resetCheckBox != null) {
            resetCheckBox.setText(getString("option.reset"));
        }
        if (linkCheckBox != null) {
            linkCheckBox.setText(getString("option.link"));
        }
        if (rfc2217CheckBox != null) {
            rfc2217CheckBox.setText(getString("option.rfc2217"));
        }
        if (cacheClearCheckBox != null) {
            cacheClearCheckBox.setText(getString("clear.cache"));
        }
        if (serialSettingsCheckBox != null) {
            serialSettingsCheckBox.setText(getString("serial.settings"));
        }
        if (enableShortConnectionCheckBox != null) {
            enableShortConnectionCheckBox.setText(getString("enable.short.connection"));
        }
        // 更新工作模式下拉框选项
        if (workModeComboBox != null) {
            String currentSelection = (String) workModeComboBox.getSelectedItem();
            workModeComboBox.removeAllItems();
            workModeComboBox.addItem(getString("work.mode.udp.client"));
            workModeComboBox.addItem(getString("work.mode.tcp.client"));
            workModeComboBox.addItem(getString("work.mode.tcp.server"));
            // 尝试恢复之前的选择
            if (currentSelection != null) {
                try {
                    // 尝试根据旧值找到对应的新值
                    if (currentSelection.contains("UDP")) {
                        workModeComboBox.setSelectedItem(getString("work.mode.udp.client"));
                    } else if (currentSelection.contains("TCP Client")) {
                        workModeComboBox.setSelectedItem(getString("work.mode.tcp.client"));
                    } else if (currentSelection.contains("TCP Server")) {
                        workModeComboBox.setSelectedItem(getString("work.mode.tcp.server"));
                    }
                } catch (Exception e) {
                    // 如果恢复失败,选择第一项
                    if (workModeComboBox.getItemCount() > 0) {
                        workModeComboBox.setSelectedIndex(0);
                    }
                }
            }
        }
        // 更新校验位下拉框选项
        if (parityComboBox != null) {
            String currentSelection = (String) parityComboBox.getSelectedItem();
            parityComboBox.removeAllItems();
            parityComboBox.addItem(getString("parity.none"));
            // 恢复之前的选择
            if (currentSelection != null && currentSelection.equals("NONE")) {
                parityComboBox.setSelectedItem(getString("parity.none"));
            } else if (parityComboBox.getItemCount() > 0) {
                parityComboBox.setSelectedIndex(0);
            }
        }
        // 更新表格列名
        updateTableColumnNames();
        revalidate();
        repaint();
    }
    /**
     * 更新所有参数行的标签文本
     */
    private void updateParameterRowLabels() {
        // 需要带星号的参数键列表(根据 createParameterRow 调用时的 withStar 参数)
        Set<String> keysWithStar = new HashSet<>();
        keysWithStar.add("ip.address.type");
        keysWithStar.add("module.static.ip");
        keysWithStar.add("subnet.mask");
        keysWithStar.add("gateway");
        // 更新所有保存的标签
        for (Map.Entry<String, JLabel> entry : parameterLabels.entrySet()) {
            String paramKey = entry.getKey();
            JLabel label = entry.getValue();
            if (label != null) {
                String labelText = getString(paramKey);
                // 如果这个参数需要星号,添加星号
                if (keysWithStar.contains(paramKey)) {
                    labelText += " ★";
                }
                label.setText(labelText);
            }
        }
    }
    /**
     * 更新表格列名
     */
    private void updateTableColumnNames() {
        if (deviceTable != null && deviceTable.getModel() instanceof javax.swing.table.DefaultTableModel) {
            javax.swing.table.DefaultTableModel model = (javax.swing.table.DefaultTableModel) deviceTable.getModel();
            String[] columnNames = {
                getString("select"),
                getString("device.ip"),
@@ -306,29 +1089,31 @@
                getString("mac.address"),
                getString("version")
            };
            // 这里需要更新表格列名,为了简单起见,我们只更新边框标题
            JViewport viewport = (JViewport) deviceTable.getParent();
            if (viewport != null) {
                JScrollPane scrollPane = (JScrollPane) viewport.getParent();
                if (scrollPane != null) {
                    scrollPane.setBorder(BorderFactory.createTitledBorder(getString("device.list")));
            // 保存当前数据
            int rowCount = model.getRowCount();
            Object[][] data = new Object[rowCount][columnNames.length];
            for (int i = 0; i < rowCount; i++) {
                for (int j = 0; j < columnNames.length; j++) {
                    if (j < model.getColumnCount()) {
                        data[i][j] = model.getValueAt(i, j);
                    }
                }
            }
            // 更新列名和数据
            model.setColumnIdentifiers(columnNames);
        }
        // 更新设置面板边框标题
        if (basicSettingsPanel != null) {
            basicSettingsPanel.setBorder(BorderFactory.createTitledBorder(getString("basic.settings")));
        }
        if (portSettingsPanel != null) {
            portSettingsPanel.setBorder(BorderFactory.createTitledBorder(getString("port.settings")));
        }
        revalidate();
        repaint();
    }
    private String getString(String key) {
        return mainFrame.getString(key);
    }
    /**
     * 在搜索开始时调用,清空旧数据并准备新搜索
     */
    private void prepareSearch() {
        clearDeviceTable();
    }
}