#include "dialogcamera.h" #include "ui_dialogcamera.h" #include #include #include #include #include "VrLog.h" #include "VrNetUtils.h" #include "StyledMessageBox.h" #include "WheelMeasurePresenter.h" #include "PathManager.h" DialogCamera::DialogCamera(QWidget *parent) : QDialog(parent), ui(new Ui::DialogCamera) { ui->setupUi(this); // 隐藏标题栏 // setWindowFlags(Qt::FramelessWindowHint); // 初始化表格 InitTable(); // 加载已有的相机配置 LoadExistingCameras(); // 刷新显示 RefreshCameraList(); } DialogCamera::~DialogCamera() { delete ui; } void DialogCamera::SetPresenter(WheelMeasurePresenter* presenter) { m_presenter = presenter; // 重新加载已有的相机配置 LoadExistingCameras(); // 刷新显示 RefreshCameraList(); } void DialogCamera::InitTable() { // 设置表格属性 ui->tableWidget_cameras->setColumnCount(4); ui->tableWidget_cameras->setHorizontalHeaderLabels({"编号", "名称", "IP地址", "操作"}); // 设置表头样式(白色字体) ui->tableWidget_cameras->horizontalHeader()->setStyleSheet( "QHeaderView::section {" " color: rgb(239, 241, 245);" " background-color: rgb(50, 52, 58);" " padding: 8px;" " border: none;" " font-size: 14px;" "}" ); // 设置列宽模式:编号和操作固定宽度,名称和IP拉伸填充 QHeaderView* header = ui->tableWidget_cameras->horizontalHeader(); header->setSectionResizeMode(0, QHeaderView::Fixed); // 编号列固定 header->setSectionResizeMode(1, QHeaderView::Stretch); // 名称列拉伸 header->setSectionResizeMode(2, QHeaderView::Stretch); // IP地址列拉伸 header->setSectionResizeMode(3, QHeaderView::Fixed); // 操作列固定 // 设置固定列的宽度 ui->tableWidget_cameras->setColumnWidth(0, 60); // 编号列 ui->tableWidget_cameras->setColumnWidth(3, 200); // 操作列(上移、下移、删除) // 设置表格样式 ui->tableWidget_cameras->horizontalHeader()->setStretchLastSection(false); ui->tableWidget_cameras->verticalHeader()->setVisible(false); ui->tableWidget_cameras->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableWidget_cameras->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableWidget_cameras->setSelectionMode(QAbstractItemView::SingleSelection); // 设置字体大小 QFont font = ui->tableWidget_cameras->font(); font.setPointSize(14); ui->tableWidget_cameras->setFont(font); } void DialogCamera::LoadExistingCameras() { m_cameraConfigs.clear(); // 从Presenter获取配置 if (m_presenter) { WheelMeasureConfigResult* configResult = m_presenter->GetConfigResult(); if (configResult) { // 从cameras加载相机配置 for (const auto& camera : configResult->cameras) { m_cameraConfigs.push_back(camera); } LOG_INFO("Loaded %zu existing cameras from config\n", m_cameraConfigs.size()); } else { LOG_WARNING("ConfigResult is null\n"); } } else { LOG_WARNING("Presenter is not set\n"); } } void DialogCamera::RefreshCameraList() { // 清空表格 ui->tableWidget_cameras->setRowCount(0); // 填充数据 for (size_t i = 0; i < m_cameraConfigs.size(); ++i) { int row = ui->tableWidget_cameras->rowCount(); ui->tableWidget_cameras->insertRow(row); // 编号列 QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(m_cameraConfigs[i].cameraIndex)); indexItem->setTextAlignment(Qt::AlignCenter); ui->tableWidget_cameras->setItem(row, 0, indexItem); // 名称列 QTableWidgetItem* nameItem = new QTableWidgetItem(QString::fromStdString(m_cameraConfigs[i].name)); nameItem->setTextAlignment(Qt::AlignCenter); ui->tableWidget_cameras->setItem(row, 1, nameItem); // IP地址列 QTableWidgetItem* ipItem = new QTableWidgetItem(QString::fromStdString(m_cameraConfigs[i].cameraIP)); ipItem->setTextAlignment(Qt::AlignCenter); ui->tableWidget_cameras->setItem(row, 2, ipItem); // 操作列 - 上移、下移、删除按钮 QWidget* btnContainer = new QWidget(); QHBoxLayout* btnLayout = new QHBoxLayout(btnContainer); btnLayout->setContentsMargins(2, 2, 2, 2); btnLayout->setSpacing(4); // 上移按钮 QPushButton* upBtn = new QPushButton("↑"); upBtn->setFixedSize(40, 35); upBtn->setStyleSheet( "QPushButton {" " color: rgb(221, 225, 233);" " background-color: rgb(60, 120, 180);" " border: none;" " border-radius: 3px;" " font-size: 16px;" " font-weight: bold;" "}" "QPushButton:hover {" " background-color: rgb(80, 140, 200);" "}" "QPushButton:pressed {" " background-color: rgb(40, 100, 160);" "}" "QPushButton:disabled {" " background-color: rgb(80, 80, 80);" " color: rgb(120, 120, 120);" "}" ); upBtn->setProperty("row", row); upBtn->setEnabled(row > 0); // 第一行禁用上移 connect(upBtn, &QPushButton::clicked, this, &DialogCamera::onMoveUpClicked); // 下移按钮 QPushButton* downBtn = new QPushButton("↓"); downBtn->setFixedSize(40, 35); downBtn->setStyleSheet( "QPushButton {" " color: rgb(221, 225, 233);" " background-color: rgb(60, 120, 180);" " border: none;" " border-radius: 3px;" " font-size: 16px;" " font-weight: bold;" "}" "QPushButton:hover {" " background-color: rgb(80, 140, 200);" "}" "QPushButton:pressed {" " background-color: rgb(40, 100, 160);" "}" "QPushButton:disabled {" " background-color: rgb(80, 80, 80);" " color: rgb(120, 120, 120);" "}" ); downBtn->setProperty("row", row); downBtn->setEnabled(row < static_cast(m_cameraConfigs.size()) - 1); // 最后一行禁用下移 connect(downBtn, &QPushButton::clicked, this, &DialogCamera::onMoveDownClicked); // 删除按钮 QPushButton* deleteBtn = new QPushButton("删除"); deleteBtn->setFixedSize(60, 35); deleteBtn->setStyleSheet( "QPushButton {" " color: rgb(221, 225, 233);" " background-color: rgb(200, 50, 50);" " border: none;" " border-radius: 3px;" " padding: 5px 10px;" "}" "QPushButton:hover {" " background-color: rgb(220, 70, 70);" "}" "QPushButton:pressed {" " background-color: rgb(180, 30, 30);" "}" ); deleteBtn->setProperty("row", row); connect(deleteBtn, &QPushButton::clicked, this, &DialogCamera::onDeleteCameraClicked); btnLayout->addWidget(upBtn); btnLayout->addWidget(downBtn); btnLayout->addWidget(deleteBtn); ui->tableWidget_cameras->setCellWidget(row, 3, btnContainer); // 设置行高 ui->tableWidget_cameras->setRowHeight(row, 45); } // 更新添加按钮状态 UpdateAddButtonState(); LOG_DEBUG("Refreshed camera list, total: %zu cameras\n", m_cameraConfigs.size()); } void DialogCamera::on_btn_add_camera_clicked() { QString name = ui->lineEdit_name->text().trimmed(); QString ip = ui->lineEdit_ip->text().trimmed(); LOG_DEBUG("ADD Camera: name=%s, ip=%s\n", name.toStdString().c_str(), ip.toStdString().c_str()); if (AddCamera(name, ip)) { // 清空输入框 ui->lineEdit_name->clear(); ui->lineEdit_ip->clear(); // 刷新显示 RefreshCameraList(); LOG_INFO("Camera added successfully: %s (%s)\n", name.toStdString().c_str(), ip.toStdString().c_str()); } } bool DialogCamera::AddCamera(const QString& name, const QString& ip) { // 检查是否已达到最大数量 if (static_cast(m_cameraConfigs.size()) >= MAX_CAMERAS) { StyledMessageBox::warning(this, "限制", QString("最多只能添加%1个相机!").arg(MAX_CAMERAS)); return false; } // 检查名称是否为空 if (name.isEmpty()) { StyledMessageBox::warning(this, "错误", "请输入相机名称!"); return false; } // 验证IP格式 bool bValid = ValidateIPAddress(ip); LOG_DEBUG("ValidateIPAddress ret: %d\n", bValid); if (!bValid) { StyledMessageBox::warning(this, "错误", "IP地址格式不正确!\n格式应为: xxx.xxx.xxx.xxx"); return false; } // 检查IP是否已存在 for (const auto& config : m_cameraConfigs) { if (config.cameraIP == ip.toStdString()) { StyledMessageBox::warning(this, "错误", "该IP地址已存在!"); return false; } } // 添加到列表 WheelCameraParam camera; camera.cameraIndex = static_cast(m_cameraConfigs.size()) + 1; camera.name = name.toStdString(); camera.cameraIP = ip.toStdString(); camera.enabled = true; m_cameraConfigs.push_back(camera); return true; } void DialogCamera::onDeleteCameraClicked() { QPushButton* btn = qobject_cast(sender()); if (!btn) return; int row = btn->property("row").toInt(); // 确认删除 QMessageBox::StandardButton reply = StyledMessageBox::question( this, "确认删除", QString("确定要删除相机 %1 吗?").arg(row + 1), QMessageBox::Yes | QMessageBox::No ); if (reply == QMessageBox::Yes) { RemoveCamera(row); RefreshCameraList(); LOG_INFO("Camera %d deleted\n", row + 1); } } void DialogCamera::onMoveUpClicked() { QPushButton* btn = qobject_cast(sender()); if (!btn) return; int row = btn->property("row").toInt(); if (row <= 0 || row >= static_cast(m_cameraConfigs.size())) { return; } // 交换当前行和上一行 std::swap(m_cameraConfigs[row], m_cameraConfigs[row - 1]); // 重新分配编号 for (size_t i = 0; i < m_cameraConfigs.size(); ++i) { m_cameraConfigs[i].cameraIndex = static_cast(i) + 1; } // 刷新显示 RefreshCameraList(); LOG_INFO("Camera moved up: row %d -> %d\n", row + 1, row); } void DialogCamera::onMoveDownClicked() { QPushButton* btn = qobject_cast(sender()); if (!btn) return; int row = btn->property("row").toInt(); if (row < 0 || row >= static_cast(m_cameraConfigs.size()) - 1) { return; } // 交换当前行和下一行 std::swap(m_cameraConfigs[row], m_cameraConfigs[row + 1]); // 重新分配编号 for (size_t i = 0; i < m_cameraConfigs.size(); ++i) { m_cameraConfigs[i].cameraIndex = static_cast(i) + 1; } // 刷新显示 RefreshCameraList(); LOG_INFO("Camera moved down: row %d -> %d\n", row + 1, row + 2); } void DialogCamera::RemoveCamera(int row) { if (row >= 0 && row < static_cast(m_cameraConfigs.size())) { m_cameraConfigs.erase(m_cameraConfigs.begin() + row); // 重新分配编号 for (size_t i = 0; i < m_cameraConfigs.size(); ++i) { m_cameraConfigs[i].cameraIndex = static_cast(i) + 1; } } } void DialogCamera::on_btn_save_clicked() { if (m_cameraConfigs.empty()) { StyledMessageBox::warning(this, "提示", "请至少添加一个相机!"); return; } // 保存配置 if (SaveConfigToFile()) { StyledMessageBox::information(this, "成功", "相机配置已保存!\n需要重启应用才能生效。"); emit configSaved(); accept(); } else { StyledMessageBox::warning(this, "失败", "保存配置失败!"); } } void DialogCamera::on_btn_cancel_clicked() { reject(); } bool DialogCamera::ValidateIPAddress(const QString& ip) { // 清理输入:去除首尾空白字符 QString cleanIp = ip.trimmed(); if (cleanIp.isEmpty()) { return false; } // 转换为C字符串 QByteArray ipBytes = cleanIp.toLatin1(); const char* ipStr = ipBytes.constData(); // 使用 VrNetUtils 提供的 IP 验证函数 bool isValid = CVrNetUtils::IsValidIP(ipStr); if (isValid) { LOG_INFO("IP validation successful: %s\n", ipStr); } else { LOG_WARNING("IP validation failed: %s\n", ipStr); } return isValid; } void DialogCamera::UpdateAddButtonState() { // 如果已达到最大数量,禁用添加按钮 bool canAdd = static_cast(m_cameraConfigs.size()) < MAX_CAMERAS; ui->btn_add_camera->setEnabled(canAdd); if (!canAdd) { ui->lineEdit_name->setEnabled(false); ui->lineEdit_ip->setEnabled(false); ui->lineEdit_name->setPlaceholderText("已达到最大数量"); ui->lineEdit_ip->setPlaceholderText("已达到最大数量"); } else { ui->lineEdit_name->setEnabled(true); ui->lineEdit_ip->setEnabled(true); ui->lineEdit_name->setPlaceholderText("例如: 相机1"); ui->lineEdit_ip->setPlaceholderText("例如: 192.168.1.100"); } } bool DialogCamera::SaveConfigToFile() { if (!m_presenter) { LOG_ERROR("Presenter is not set, cannot save configuration\n"); return false; } try { WheelMeasureConfigResult* configResult = m_presenter->GetConfigResult(); IVrWheelMeasureConfig* vrConfig = m_presenter->GetConfig(); if (!configResult || !vrConfig) { LOG_ERROR("ConfigResult or IVrWheelMeasureConfig is null\n"); return false; } // 更新ConfigResult中的cameras configResult->cameras.clear(); for (const auto& camera : m_cameraConfigs) { configResult->cameras.push_back(camera); LOG_INFO(" Camera %d: %s (IP: %s)\n", camera.cameraIndex, camera.name.c_str(), camera.cameraIP.c_str()); } // 保存配置到文件 std::string configFilePath = PathManager::GetInstance().GetConfigFilePath().toStdString(); bool saveResult = vrConfig->SaveConfig(configFilePath, *configResult); if (saveResult) { LOG_INFO("Camera configuration saved successfully to: %s\n", configFilePath.c_str()); } else { LOG_ERROR("Failed to save camera configuration to file\n"); } return saveResult; } catch (const std::exception& e) { LOG_ERROR("Exception while saving camera configuration: %s\n", e.what()); return false; } catch (...) { LOG_ERROR("Unknown exception while saving camera configuration\n"); return false; } } std::vector DialogCamera::GetCameraConfigs() const { return m_cameraConfigs; }