You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PayloadAPP/rescueloadwidget.cpp

364 lines
13 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "rescueloadwidget.h"
#include <QQuickWidget>
#include "qjsonarray.h"
#include "ui_rescueloadwidget.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QQuickView>
#include <QUrl>
#include <QRandomGenerator>
#include <QTextBlock>
#include <QtQml>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QFileDialog>
#include <QMessageBox>
RescueLoadWidget::RescueLoadWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::RescueLoadWidget)
{
ui->setupUi(this);
initialModel(); // 初始化数据model
initialUi(); // 初始化表格样式
// 数据交互和视图设置
rescueLoad = new RescueLoad(this);
rescueLoad->startCommunication(); // todo: 转移到子线程中运行
// rescueLoad->sendMessage(QString("Hello"));
connect(rescueLoad, &RescueLoad::dataUpdate, rescueLoad, [=](ImsiData data){
imsiDataModel->updateData(data);
});
// 地图组件, 必须在RescueLoad和ImsiDataModel初始化后加载
openQLocationMap();
}
RescueLoadWidget::~RescueLoadWidget()
{
ui->deviceDetail->clearContents();
delete protoItem;
delete standardItem;
delete ui;
}
// 使用QLocation加载地图模块 (fixme: 能显示地图但是无法向qml传递数据
void RescueLoadWidget::openQLocationMap() {
QQuickView *qmlView = new QQuickView();
qmlView->rootContext()->setContextProperty("imsiDataModel", imsiDataModel); // 注意先绑定属性再设置qml
qmlView->rootContext()->setContextProperty("imsiSelectModel", ui->deviceview->selectionModel()); // 注意先绑定属性再设置qml
qmlView->setSource(QUrl("qrc:/places_map.qml"));
QWidget *container = QWidget::createWindowContainer(qmlView, this);
ui->mapGroup->setLayout(new QVBoxLayout);
ui->mapGroup->layout()->addWidget(container);
qDebug()<<"搜救地图开启"<<imsiDataModel->getDataMap().keys().size();
// 接收QML的信号
QObject* object = (QObject* )qmlView->rootObject();
// connect(object, SIGNAL(locationClicked(QString)), this, SLOT(updateDetailTable(QString)));
QObject::connect(object, SIGNAL(indexClicked(int)), this, SLOT(tableIndexClicked(int)));
}
void RescueLoadWidget::tableIndexClicked(int row){
// qDebug()<<row;
emit ui->deviceview->clicked(imsiDataModel->index(row));
}
void RescueLoadWidget::initialUi()
{
// 设备imsi列表样式
setTable(ui->deviceview);
setTable(ui->bnameview);
setTable(ui->wnameview);
// 单元格样式
protoItem = new QTableWidgetItem;
protoItem->setTextAlignment(Qt::AlignCenter);
standardItem = new QStandardItem;
standardItem->setTextAlignment(Qt::AlignCenter);
QFont font = QFont("Microsoft YaHei UI", 12);
protoItem->setFont(font);
standardItem->setFont(font);
setDeviceDetail(ui->deviceDetail);
}
void RescueLoadWidget::setTable(QTableView* tableView) {
// 设置样式表
tableView->setStyleSheet(
"QTableView::item {"
" background-color: transparent;"
" color: white;"
"}"
);
QFont font = QFont("Microsoft YaHei UI", 12);
tableView->horizontalHeader()->setFont(font);
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 可拉伸填充
tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter); //表头信息显示居中
tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);//对第2列单独设置固定宽度
tableView->setColumnWidth(1, 100);//设置固定宽度
tableView->verticalHeader()->setFont(font);
tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
tableView->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
tableView->verticalHeader()->setFixedWidth(35); // 行表头(序号)设置固定宽度
// tableWidget->verticalHeader()->hide(); //将默认序号隐藏
tableView->setShowGrid(true);
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 不可编辑
// 选中行更新详细信息
tableView->setSelectionBehavior(QAbstractItemView::SelectRows); // 选中行
// 单击后选中并显示详情,再次点击取消选中
connect(tableView, &QTableView::clicked, this, [=](QModelIndex index) {
static int preRow = -1; // 记录前一个点击事件所在行
int curRow = index.row();
QModelIndex imsiIndex = index.model()->index(curRow, 0); // note 第一列必须为imsi值
QString imsi =tableView->model()->data(imsiIndex).toString();
QItemSelectionModel* selectModel = tableView->selectionModel();
if (curRow == preRow) {
// 取消选中状态
if (selectModel->isSelected(index)) {
selectModel->select(index, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
preRow = -1; //取消后重置,否则无法选中
return;
}
}
selectModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
preRow = curRow;
if (tableView == ui->deviceview){
updateDetailTable(imsi);
}
});
// 选中行更新名单编辑区
connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged, tableView, [=]() {
QModelIndexList selectedIndexes = tableView->selectionModel()->selectedIndexes();
QAbstractItemModel* model = tableView->model();
ui->namelistEdit->clear();
QString selectedText;
for (const QModelIndex &index : selectedIndexes) {
if (index.column() == 0) {
selectedText = model->data(index).toString();
ui->namelistEdit->appendPlainText(selectedText.trimmed());
}
}
ui->namelistEdit->show();
// qDebug() << "选择状态变更: selcted: " << selectedIndexes;
});
}
void RescueLoadWidget::initialModel()
{
QStringList headers = QStringList()<<"IMSI"<<"运营商";
wnamelistModel = new QStandardItemModel(this);
wnamelistModel->setHorizontalHeaderLabels(headers);
wnamelistModel->setColumnCount(2);
ui->wnameview->setModel(wnamelistModel);
bnamelistModel = new QStandardItemModel(this);
bnamelistModel->setHorizontalHeaderLabels(headers);
bnamelistModel->setColumnCount(2);
ui->bnameview->setModel(bnamelistModel);
imsiDataModel = new ImsiTableModel(this);
ui->deviceview->setModel(imsiDataModel);
}
void RescueLoadWidget::setDeviceDetail(QTableWidget* deviceDetail) {
// 设备详情表样式
deviceDetail->setStyleSheet(
"QTableWidget::item {"
" background-color: transparent;"
" color: white;"
"}"
);
deviceDetail->verticalHeader()->setFont(QFont("Microsoft YaHei UI", 12));
deviceDetail->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
deviceDetail->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
deviceDetail->setEditTriggers(QAbstractItemView::NoEditTriggers); // 不可编辑
deviceDetail->setShowGrid(true);
// 初始化
for (int i=0; i<deviceDetail->rowCount(); i++) {
QTableWidgetItem *item = protoItem->clone();
deviceDetail->setItem(i, 0, item);
}
deviceDetail->show();
qDebug() << "设备详细信息初始化完成";
}
// 更新指定imsi的详细信息
void RescueLoadWidget::updateDetailTable(const QString imsi)
{
const QHash<QString, ImsiData>& dataMap = imsiDataModel->getDataMap();
if (!dataMap.contains(imsi)) return;
ImsiData data = imsiDataModel->getDataMap().value(imsi);
// qDebug()<<"更新详细信息start: " << imsi;
emit imsiDataModel->detailUpdated(imsi, data.longitude.toDouble(), data.latitude.toDouble());
ui->deviceDetail->item(0, 0)->setText(data.imsi);
ui->deviceDetail->item(1, 0)->setText(data.operatorName);
ui->deviceDetail->item(2, 0)->setText(data.longitude);
ui->deviceDetail->item(3, 0)->setText(data.latitude);
ui->deviceDetail->item(4, 0)->setText(QString::number(data.altitude));
ui->deviceDetail->item(5, 0)->setText(data.fcn);
ui->deviceDetail->item(6, 0)->setText(QString::number(data.rssi));
ui->deviceDetail->item(7, 0)->setText(data.createDate);
ui->deviceDetail->show();
// qDebug()<<"更新详细信息end: " << imsi;
}
slots void RescueLoadWidget::on_start4G_clicked()
{
// 开启4g功放
rescueLoad->sendMessage(QString("{\"cmd\": \"startCell\"}"));
rescueLoad->sendMessage(QString("{\"cmd\": \"heartbeat\"}"));
// 时间同步
rescueLoad->syncTime();
}
slots void RescueLoadWidget::on_stop4G_clicked()
{
rescueLoad->sendMessage(QString("{\"cmd\": \"stopCell\"}"));
}
slots void RescueLoadWidget::on_start5G_clicked()
{
// 开启5g功放
rescueLoad->sendMessage(QString("{\"cmd\": \"startCell_5g\"}"));
rescueLoad->sendMessage(QString("{\"cmd\": \"heartbeat\"}"));
// 时间同步
rescueLoad->syncTime();
}
slots void RescueLoadWidget::on_stop5G_clicked()
{
rescueLoad->sendMessage(QString("{\"cmd\": \"stopCell_5g\"}"));
}
slots void RescueLoadWidget::on_addblistBtn_clicked()
{
QList<QString> namelistToSend = getNameListEditList(); // 输入量用于更新namelist
QString type = ui->namelistConfigType->currentText().toUpper();
QString sendType;
if (type.startsWith("ADD")) {
sendType = "ADD";
} else if (type.startsWith("SUB")) {
sendType = "SUB";
} else if (type.startsWith("SAVE")) {
sendType = "SAVE";
} else {
return;
}
rescueLoad->sendNameList("block", sendType, QList<QString>(), namelistToSend);
updateWBnamelist("B", sendType, namelistToSend);
}
slots void RescueLoadWidget::on_addwlistBtn_clicked()
{
QList<QString> namelistToSend = getNameListEditList(); // 输入量用于更新namelist
QString type = ui->namelistConfigType->currentText().toUpper();
QString sendType;
if (type.startsWith("ADD")) {
sendType = "ADD";
} else if (type.startsWith("SUB")) {
sendType = "SUB";
} else if (type.startsWith("SAVE")) {
sendType = "SAVE";
} else {
return;
}
rescueLoad->sendNameList("block", sendType, namelistToSend, QList<QString>());
updateWBnamelist("W", sendType, namelistToSend);
}
/** 获取编辑区的imsi列表*/
QList<QString> RescueLoadWidget::getNameListEditList(){
QTextBlock block = ui->namelistEdit->document()->firstBlock();
QList<QString> namelist;
while (block.isValid()) {
QString tmp = block.text().trimmed();
if (! tmp.isEmpty()) {
namelist.append(tmp);
}
block = block.next();
}
return namelist;
}
// 更新黑名单和白名单的数据与显示
void RescueLoadWidget::updateWBnamelist(QString listType, QString sendType, QList<QString> &namelistToUpdate)
{
QStandardItemModel *namelistModel = listType=="W"? wnamelistModel: bnamelistModel;
QSet<QString> &namelistToShow = listType=="W"? wnamelist : bnamelist;
// 更新黑/白名单列表
if (sendType == "ADD") { // 新增
for(const QString &imsi: namelistToUpdate) {
namelistToShow.insert(imsi);
}
} else if (sendType == "SUB") { // 删除
for(const QString &imsi: namelistToUpdate) {
namelistToShow.remove(imsi);
}
} else if (sendType == "SAVE") { // 替换现有在列表
namelistToShow.clear();
for(const QString &imsi: namelistToUpdate) {
namelistToShow.insert(imsi);
}
}
// 列表显示更新
namelistModel->clear();
namelistModel->setColumnCount(2);
namelistModel->setRowCount(namelistToShow.size());
namelistModel->setHorizontalHeaderLabels(QStringList()<<"IMSI"<<"运营商");
int i = 0;
for (const QString &imsi : namelistToShow) {
QStandardItem *item1 =standardItem->clone();
QStandardItem *item2 =standardItem->clone();
item1->setText(imsi);
item2->setText(ImsiData::getOperatorNameByImsi(imsi));
namelistModel->setItem(i, 0, item1);
namelistModel->setItem(i, 1, item2);
i ++ ;
}
qDebug() << "名单数据更新end"<< namelistModel->rowCount();
}
void RescueLoadWidget::on_ipportBtn_clicked()
{
QString newIp = ui->ipEdit->text().trimmed();
int newPort = ui->portEdit->text().trimmed().toInt();
rescueLoad->remoteIp = newIp;
rescueLoad->remotePort = newPort;
}
void RescueLoadWidget::on_saveFileButton_clicked()
{
QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss");
QString defaultPath = QString("%1/搜救信息%2.csv").arg(imsiDataModel->getSaveDir(), timeStr);
QString filePath = QFileDialog::getSaveFileName(this, tr("保存文件"), defaultPath, tr("CSV 文件 (*.csv)"));
qDebug()<< filePath;
if (!filePath.isEmpty()) {
imsiDataModel->saveDataListToCsv(filePath);
}
}