PowerMaster/source/alarmEventDataView.cpp

621 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "alarmEventDataView.h"
#include <QHeaderView>
#include <QVBoxLayout>
#include <QPainter>
#include <QTimer>
#include <QRandomGenerator>
#include <QMouseEvent>
//#include <QApplication>
///////------AlarmEventDataModel-----
AlarmEventDataModel::AlarmEventDataModel(AlarmDataMode mode, QObject* parent)
: QAbstractTableModel(parent)
, m_dataMode(mode)
, m_maxRealTimeEvents(5)
{
if(m_dataMode == RealTime) //创建几个“空事件”来初始化表格
{
for(int i = 0; i < m_maxRealTimeEvents; ++i)
{
EventData event;
event.id = ""; //空事件
m_displayEvents.append(event);
}
}
m_paginationInfo.entriesPerPage = 100;
m_paginationInfo.currentPage = 1;
m_paginationInfo.totalEntries = 0;
iniHeaderData();
//实时数据测试
m_simulatedDataTimer = new QTimer(this);
connect(m_simulatedDataTimer, &QTimer::timeout, this, &AlarmEventDataModel::onTimeoutSimulateData);
m_simulatedDataTimer->start(3000);
}
AlarmEventDataModel::~AlarmEventDataModel()
{}
QModelIndex AlarmEventDataModel::index(int row, int column, const QModelIndex& parent) const
{
if(!hasIndex(row, column, parent))
return QModelIndex();
if(column > m_headerData.count())
return QModelIndex();
return createIndex(row, column);
}
QVariant AlarmEventDataModel::data(const QModelIndex& index, int role) const
{
if(!index.isValid())
return QVariant();
int row = index.row();
int col = index.column();
int globalRow = (m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage + row;
const EventData& event = m_displayEvents.at(row);
if(event.id.isEmpty()) //无效事件
return QVariant();
//EventData event = m_displayEvents[row];
switch (role)
{
case Qt::DisplayRole:
{
switch(col)
{
case Index:
return QString::number(globalRow + 1);
case ReceiveTime:
return QDateTime::fromMSecsSinceEpoch(event.timestamp).toString("yyyy-MM-dd hh:mm:ss");
case SOETime:
return QDateTime::fromMSecsSinceEpoch(event.timestamp).toString("yyyy-MM-dd hh:mm:ss");
case Station:
return event.stationName;
case Bay:
return event.bayName;
case Description:
return event.description;
case Type:
return event.type;
case Severity:
return event.severity;
case Status:
{
if(event.status < 3)
return QString("未确认");
else
return QString("已确认");
}
default:
return QVariant();
}
}
case Qt::ForegroundRole:
{
switch(col)
{
case Severity:
{
if(event.severity == "事故")
return QColor(255, 85, 0);
else if(event.severity == "异常")
return QColor(255, 170, 0);
else if(event.severity == "预警")
return QColor(0, 170, 255);
else if(event.severity == "告知")
return QColor(0, 170, 0);
else
return QColor(250, 250, 250);
}
case Status:
{
if(event.status < 3)
return QColor(0, 170, 255);
else
return QColor(0, 170, 0);
}
default:
return QColor(250, 250, 250);
}
}
case Qt::TextAlignmentRole:
return Qt::AlignCenter; //居中展示
default:
return QVariant();
}
}
QVariant AlarmEventDataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
return m_headerData.at(section).text;
return QAbstractItemModel::headerData(section, orientation, role);
}
int AlarmEventDataModel::rowCount(const QModelIndex& parent) const
{
return m_displayEvents.count();
}
int AlarmEventDataModel::columnCount(const QModelIndex& parent) const
{
return m_headerData.isEmpty() ? 0 : m_headerData.count();
}
Qt::ItemFlags AlarmEventDataModel::flags(const QModelIndex& index) const
{
if(!index.isValid())
return Qt::NoItemFlags;
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
flags |= Qt::ItemIsEditable; //不可编辑
return flags;
}
void AlarmEventDataModel::iniHeaderData()
{
m_headerData.emplace_back(SectionData("序号", 90, Index));
m_headerData.emplace_back(SectionData("接收时间", 200, ReceiveTime));
m_headerData.emplace_back(SectionData("SOE时间", 200, SOETime));
m_headerData.emplace_back(SectionData("厂站", 200, Station));
m_headerData.emplace_back(SectionData("间隔", 200, Bay));
m_headerData.emplace_back(SectionData("信息", -1, Description));
m_headerData.emplace_back(SectionData("类型", 150, Type));
m_headerData.emplace_back(SectionData("等级", 150, Severity));
m_headerData.emplace_back(SectionData("确认状态", 150, Status));
m_headerData.emplace_back(SectionData("操作", 172, Operation));
}
/*void AlarmEventDataModel::setMode(AlarmDataMode mode)
{
if(m_dataMode == mode)
return;
m_dataMode = mode;
if(mode == Historical)
{}
else
{}
}*/
void AlarmEventDataModel::setMaxRealTimeEvents(int count)
{
if(m_dataMode == Historical) //实时列表初始化表格
{
if(m_maxRealTimeEvents == count)
return;
else if(m_maxRealTimeEvents < count)
{
int DValue = count - m_maxRealTimeEvents;
for(int i = 0; i < DValue; ++i)
m_displayEvents.removeLast();
}
else if(m_maxRealTimeEvents > count)
{
int DValue = m_maxRealTimeEvents - count;
for(int i = 0; i < DValue; ++i)
{
EventData event;
event.id = ""; //空事件
m_displayEvents.append(event);
}
}
m_maxRealTimeEvents = count;
}
}
void AlarmEventDataModel::setFilter(const AlarmEventDataFilter& filter)
{
m_currentFilter = filter;
refresh();
}
void AlarmEventDataModel::applyFilter()
{
m_filteredEvents.clear();
if(m_allEvents.size() > 0)
m_filteredEvents = m_currentFilter.apply(m_allEvents);
}
void AlarmEventDataModel::refresh()
{
m_allEvents.clear();
//1.通过服务获取当前时间段的所有事件-m_allEvents
//2.过滤事件(时间区间作为服务请求参数,其它过滤在本地完成)-m_filteredEvents
applyFilter();
//3.更新页码数据
updatePaginationInfo();
//4.根据页码刷新当前页面数据()-m_displayEvents
updateCurPageData();
}
void AlarmEventDataModel::updatePaginationInfo()
{
m_paginationInfo.totalEntries = m_filteredEvents.size();
m_paginationInfo.totalPages = qCeil(static_cast<qreal>(m_paginationInfo.totalEntries) / m_paginationInfo.entriesPerPage);
if(m_paginationInfo.totalPages == 0)
m_paginationInfo.currentPage = 1;
else if(m_paginationInfo.currentPage > m_paginationInfo.totalPages)
m_paginationInfo.currentPage = m_paginationInfo.totalPages;
}
int AlarmEventDataModel::findEventDataIndexById(const QString& eventId)
{
for(int i = 0; i < m_displayEvents.size(); i++)
{
if(m_displayEvents.at(i).id == eventId)
return i;
}
return -1;
}
void AlarmEventDataModel::updateEventData(int index, const EventData& updatedEvent)
{
if(index < 0 || index >= m_displayEvents.size())
return;
m_displayEvents[index] = updatedEvent;
//更新视图
QModelIndex modelIndex = createIndex(index, 0);
emit dataChanged(modelIndex, modelIndex);
}
void AlarmEventDataModel::updateCurPageData()
{
m_displayEvents.clear();
int startIndex = (m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage;
int endIndex = qMin(startIndex + m_paginationInfo.entriesPerPage, m_filteredEvents.size());
beginResetModel();
if(startIndex < m_filteredEvents.size())
m_displayEvents = m_filteredEvents.mid(startIndex, endIndex - startIndex);
endResetModel();
}
void AlarmEventDataModel::onTimeoutSimulateData()
{
//模拟实时告警数据
static int id = 0, min = 0, max = 3;
int randomInt = min + QRandomGenerator::global()->bounded(min, max + 1);
QString strID = QString::number(++id);
//qDebug() << id << " " << strID;
EventData event;
event.id = strID;
event.name = QString("实时告警") + strID;
event.timestamp = QDateTime::currentMSecsSinceEpoch();
event.stationName = QString("厂站") + QString::number(randomInt);
event.bayName = QString("间隔") + QString::number(randomInt);
event.description = "";
event.type = 5;
QString severity = QString("预警");
if(randomInt == 0)
severity = QString("告知");
else if(randomInt == 1)
severity = QString("预警");
else if(randomInt == 2)
severity = QString("异常");
else if(randomInt == 3)
severity = QString("事故");
event.severity = severity;
event.status = 0;
onRealTimeEventReceived(event);
}
void AlarmEventDataModel::onRealTimeEventReceived(const EventData& event)
{
if(m_dataMode != RealTime)
return;
int index = findEventDataIndexById(event.id);
if(index >= 0)
{
updateEventData(index, event);
return;
}
beginResetModel();
//插入数据之前,先判断当前是否达到最大显示条目,达到的话删除最靠前(时间)的条目
if(m_displayEvents.size() >= m_maxRealTimeEvents)
m_displayEvents.removeLast();
//按照时间顺序排序(从后到前)
int insertPosition = 0;
for(; insertPosition < m_displayEvents.size(); ++insertPosition)
{
if(event.timestamp > m_displayEvents.at(insertPosition).timestamp)
break;
}
if(insertPosition < m_displayEvents.size())
m_displayEvents.insert(insertPosition, event);
else
m_displayEvents.append(event);
endResetModel();
emit receivedNewAlarm(event);
}
bool AlarmEventDataModel::setCurrentPage(int page)
{
if(m_paginationInfo.currentPage != page && page > 0 && page <= m_paginationInfo.totalPages)
{
m_paginationInfo.currentPage = page;
updateCurPageData();
return true;
}
return false;
}
void AlarmEventDataModel::previousPage()
{
if(m_paginationInfo.currentPage == 1)
return;
int page = m_paginationInfo.currentPage;
setCurrentPage(--page);
}
void AlarmEventDataModel::nextPage()
{
if(m_paginationInfo.currentPage == m_paginationInfo.totalPages)
return;
int page = m_paginationInfo.currentPage;
setCurrentPage(++page);
}
void AlarmEventDataModel::firstPage()
{
if(m_paginationInfo.currentPage == 1)
return;
setCurrentPage(1);
}
void AlarmEventDataModel::lastPage()
{
if(m_paginationInfo.currentPage == m_paginationInfo.totalPages)
return;
setCurrentPage(m_paginationInfo.totalPages);
}
///////------AlarmEventDataDelegate-----
AlarmEventDataDelegate::AlarmEventDataDelegate(QTableView* view, QObject* parent)
: QStyledItemDelegate(parent)
,m_tableView(view)
{
m_btnConfirm.text = QString("确 认");
m_btnConfirm.textColor = QColor(34, 177, 16);
m_btnConfirm.borderColor = QColor(34, 177, 16);
m_btnConfirm.borderWidth = 1;
m_btnConfirm.borderRaius = 2;
m_btnConfirm.normalBgColor = Qt::transparent;
m_btnConfirm.hoverBgColor = QColor(34, 177, 16, 80);
m_btnConfirm.pressedBgColor = Qt::transparent;
m_btnReplay.text = QString("回 放");
m_btnReplay.textColor = QColor(86, 156, 214);
m_btnReplay.borderColor = QColor(86, 156, 214);
m_btnReplay.borderWidth = 1;
m_btnReplay.borderRaius = 2;
m_btnReplay.normalBgColor = Qt::transparent;
m_btnReplay.hoverBgColor = QColor(86, 156, 214, 80);
m_btnReplay.pressedBgColor = Qt::transparent;
}
AlarmEventDataDelegate::~AlarmEventDataDelegate()
{}
void AlarmEventDataDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
//根据行号设置交替颜色
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
if((index.row() + 1) % 2 == 0)
painter->fillRect(opt.rect, QColor(11, 26, 33, 100));
else
painter->fillRect(opt.rect, QColor(11, 26, 33, 0));
if(m_tableView)
{
//绘制单元格边框(只绘制右边框,每行的最后一个单元格不绘制)
painter->save();
QPen pen(QColor(60,60,60), 1, Qt::DotLine);
painter->setPen(pen);
if(index.column() != m_tableView->model()->columnCount() - 1)
{
//opt.rect.adjust(1, 0, 1, 0);
painter->drawLine(opt.rect.topRight(), opt.rect.bottomRight());
}
painter->restore();
//绘制操作按钮
QModelIndex numIndex = m_tableView->model()->index(index.row(), 0);
QString number = numIndex.data(Qt::DisplayRole).toString();
if(!number.isEmpty() && index.column() == m_tableView->model()->columnCount() - 1)
{
int nMarginH = 10;
int nMarginV = 5;
int nSpacing = 10;
int nBtnWidth = (opt.rect.width() - nMarginH * 2 - nSpacing) * 0.5;
int nBtnHeight = opt.rect.height() - nMarginV * 2;
/*QStyleOptionButton btnConfirm;
btnConfirm.text = QString("确 认");
btnConfirm.rect = QRect(opt.rect.left() + nMarginH, opt.rect.top() + nMarginV, nBtnWidth, nBtnHeight);
btnConfirm.state |= QStyle::State_Enabled;
QStyleOptionButton btnReplay;
btnReplay.text = QString("回 放");
btnReplay.rect = QRect(btnConfirm.rect.right() + nSpacing, opt.rect.top() + nMarginV, nBtnWidth, nBtnHeight);
btnReplay.state |= QStyle::State_Enabled;
// 绘制按钮
QApplication::style()->drawControl(QStyle::CE_PushButton, &btnConfirm, painter);
QApplication::style()->drawControl(QStyle::CE_PushButtonLabel, &btnReplay, painter);*/
const_cast<AlarmEventDataDelegate*>(this)->m_btnConfirm.rect = QRect(opt.rect.left() + nMarginH, opt.rect.top() + nMarginV, nBtnWidth, nBtnHeight);
const_cast<AlarmEventDataDelegate*>(this)->m_btnReplay.rect = QRect(m_btnConfirm.rect.right() + nSpacing, opt.rect.top() + nMarginV, nBtnWidth, nBtnHeight);
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
//绘制‘确认’按钮
QPen rectPen;
rectPen.setColor(m_btnConfirm.borderColor);
rectPen.setWidth(m_btnConfirm.borderWidth);
painter->setPen(rectPen);
QColor brushColor = m_btnConfirm.normalBgColor;
bool isHover = opt.state.testFlag(QStyle::State_MouseOver) && m_btnConfirm.rect.contains(m_mousePositon); //opt.state.testFlag(QStyle::State_MouseOver)表示鼠标是否悬停在该视图项(即单元格)上
//bool isPressed = opt.state.testFlag(QStyle::State_Sunken) && m_btnConfirm.rect.contains(m_mousePositon);//opt.state.testFlag(QStyle::State_Sunken)表示鼠标是否在该视图项(即单元格)上按下
bool isPressed = m_buttonColumnIsPress && m_btnConfirm.rect.contains(m_mousePositon); //opt.state.testFlag(QStyle::State_Sunken)总是为false且未找到原因
//注意判断顺序一定要先先判断press
if(isPressed)
brushColor = m_btnConfirm.pressedBgColor;
else if(isHover)
brushColor = m_btnConfirm.hoverBgColor;
painter->setBrush(brushColor);
painter->drawRoundedRect(m_btnConfirm.rect, m_btnConfirm.borderRaius, m_btnConfirm.borderRaius);
painter->setPen(m_btnConfirm.textColor);
painter->drawText(m_btnConfirm.rect, Qt::AlignCenter, m_btnConfirm.text);
//绘制‘回放’按钮
rectPen.setColor(m_btnReplay.borderColor);
rectPen.setWidth(m_btnReplay.borderWidth);
painter->setPen(rectPen);
brushColor = m_btnReplay.normalBgColor;
isHover = opt.state.testFlag(QStyle::State_MouseOver) && m_btnReplay.rect.contains(m_mousePositon);
//isPressed = opt.state.testFlag(QStyle::State_Sunken) && isHover;
isPressed = m_buttonColumnIsPress && m_btnReplay.rect.contains(m_mousePositon);
if(isPressed)
brushColor = m_btnReplay.pressedBgColor;
else if(isHover)
brushColor = m_btnReplay.hoverBgColor;
painter->setBrush(brushColor);
painter->drawRoundedRect(m_btnReplay.rect, m_btnReplay.borderRaius, m_btnReplay.borderRaius);
painter->setPen(m_btnReplay.textColor);
painter->drawText(m_btnReplay.rect, Qt::AlignCenter, m_btnReplay.text);
painter->restore();
}
}
if(opt.state.testFlag(QStyle::State_Selected))
{
//方法1移除选中状态防止选中改变文字颜色
//opt.state &= ~QStyle::State_Selected;
//方法2
QColor originalTextColor = opt.palette.color(QPalette::Text);
opt.palette.setColor(QPalette::HighlightedText, originalTextColor);
}
//绘制默认内容
QStyledItemDelegate::paint(painter, opt, index);
}
bool AlarmEventDataDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
{
if(m_tableView && index.column() == m_tableView->model()->columnCount() - 1) //只处理操作按钮所在列的事件
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
m_mousePositon = mouseEvent->pos();
m_buttonColumnIsPress = false;
if(mouseEvent->type() == QEvent::MouseMove)
{
emit m_tableView->model()->dataChanged(index, index); //触发重绘
}
else if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QEvent::MouseButtonPress)
{
m_buttonColumnIsPress = true;
emit m_tableView->model()->dataChanged(index, index); //触发重绘
//qDebug() << option.state.testFlag(QStyle::State_Sunken);
}
else if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QEvent::MouseButtonRelease)
{
emit m_tableView->model()->dataChanged(index, index); //触发重绘
if(m_btnConfirm.rect.contains(m_mousePositon))
emit confirmBtnClicked(index);
else if(m_btnReplay.rect.contains(m_mousePositon))
emit replayBtnClicked(index);
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
///////------AlarmEventDataView-----
AlarmEventDataView::AlarmEventDataView(AlarmDataMode mode, QWidget* parent)
: QWidget(parent)
{
m_tableView = new QTableView(this);
m_tableView->verticalHeader()->setVisible(false);
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
//m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_tableView->setShowGrid(false);
//m_tableView->setStyleSheet("QHeaderView{background-color: rgb(40, 40, 40);} QHeaderView::section{background-color:transparent;}");
m_tableModel = new AlarmEventDataModel(mode, this);
m_tableView->setModel(m_tableModel);
//设置表头
const QVector<AlarmEventDataModel::SectionData> headerData = m_tableModel->headerData();
for(int i = 0; i < headerData.size(); i++)
{
if(headerData.at(i).width == -1)
m_tableView->horizontalHeader()->setSectionResizeMode(i, QHeaderView::Stretch);
else
m_tableView->setColumnWidth(i, headerData.at(i).width);
}
m_delegate = new AlarmEventDataDelegate(m_tableView, this);
connect(m_delegate, &AlarmEventDataDelegate::confirmBtnClicked, this, &AlarmEventDataView::onBtnClicked_Confirm);
connect(m_delegate, &AlarmEventDataDelegate::replayBtnClicked, this, &AlarmEventDataView::onBtnClicked_Replay);
m_tableView->setItemDelegate(m_delegate);
m_vLayout = new QVBoxLayout(this);
m_vLayout->setSpacing(0);
m_vLayout->setContentsMargins(0, 0, 0, 0);
m_vLayout->addWidget(m_tableView);
this->setLayout(m_vLayout);
}
AlarmEventDataView::~AlarmEventDataView()
{}
/*void AlarmEventDataView::setModelMode(AlarmDataMode mode, int maxRealTimeEvents)
{
if(m_tableModel)
{
m_tableModel->setMode(mode);
if(mode == RealTime)
m_tableModel->setMaxRealTimeEvents(maxRealTimeEvents);
}
}*/
void AlarmEventDataView::onBtnClicked_Confirm(const QModelIndex& index)
{
qDebug() << QString("confirmBtnClicked, row: %1").arg(index.row());
}
void AlarmEventDataView::onBtnClicked_Replay(const QModelIndex& index)
{
qDebug() << QString("replayBtnClicked, row: %1").arg(index.row());
}