#include "WindowAppVariableTable.h"
#include "GvlManager.h"
// extern VariablesManager m_VariablesManager;
// 列数
#define GVL_COLUMN_COUNT 6
#define DB_COLUMN_COUNT 7
// 表示正确状态的颜色
#define COLOR_ITEM_OK qRgb(198,239,206)
#define COLOR_ITEM_ERROR qRgb(255,199,206)
WindowAppVariableTable::WindowAppVariableTable(QWidget *parent)
: QTableWidget(parent)
, m_gvlMode( GVL_MODE::GVL_BASIC )
{
ui.setupUi(this);
}
WindowAppVariableTable::~WindowAppVariableTable()
{
}
///
/// 初始化变量表格
///
void WindowAppVariableTable::initTable(const QString& strGroup, GVL_MODE gvlMode)
{
this->m_strGroup = strGroup;
m_gvlMode = gvlMode;
// 创建变量表格
// 根据不同模式初始化不同的表格
if (m_gvlMode != GVL_MODE::GVL_DB)
{
this->initStandardTableHeader();
}
else
{
this->initDBTableHeader();
}
//设置表头字体
QFont font = this->horizontalHeader()->font();
font.setBold(true);
this->horizontalHeader()->setFont(font);
// 设置文字左对齐
this->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);
// 设置为不可编辑
//this->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 设置为整行选中模式
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setSelectionMode(QAbstractItemView::SingleSelection);
// 设置最左侧的序号不用显示
this->verticalHeader()->setVisible(false);
//设置行高
this->verticalHeader()->setDefaultSectionSize(10);
//点击表时不对表头行光亮(获取焦点)当表格只有一行的时候,则表头会出现塌陷问题
this->horizontalHeader()->setHighlightSections(false);
}
///
/// 按标准模式初始化变量表格Header
///
void WindowAppVariableTable::initStandardTableHeader()
{
// 列数
this->setColumnCount(GVL_COLUMN_COUNT);
// 设置表头文字
QStringList headers;
headers
<< ("Index")
<< ("Name")
<< ("Type")
<< ("Value")
<< ("Serialized")
<< ("Comment");
this->setHorizontalHeaderLabels(headers);
}
///
/// 按DB模式初始化变量表格Header
///
void WindowAppVariableTable::initDBTableHeader()
{
// 列数
this->setColumnCount(DB_COLUMN_COUNT);
// 设置表头文字
QStringList headers;
headers
<< ("Index")
<< ("Name")
<< ("Type")
<< ("Value")
<< ("Comm. Address")
<< ("Access")
<< ("Comment");
this->setHorizontalHeaderLabels(headers);
}
///
/// 添加新的一行
///
///
int WindowAppVariableTable::insertTableLine(
bool bSerialized,
QString strName,
QString strFullName,
QString strType,
QString strValue,
QString strComment
)
{
// 防止消息被循环触发
this->blockSignals(true);
// 获取当前行数
int nRowCount = this->rowCount();
// 添加新的一行
this->insertRow(nRowCount);
// ---Index
QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(nRowCount + 1));
indexItem->setTextAlignment(Qt::AlignCenter);
// 本列不可编辑
indexItem->setFlags(indexItem->flags() & (~Qt::ItemIsEditable));
this->setItem(nRowCount, GVL_COL_INDEX, indexItem);
// ---Name
QTableWidgetItem* nameItem = new QTableWidgetItem(strName);
this->setItem(nRowCount, GVL_COL_NAME, nameItem);
nameItem->setTextAlignment(Qt::AlignCenter);
// 不可编辑
nameItem->setFlags(nameItem->flags() & (~Qt::ItemIsEditable));
// ---Type
QTableWidgetItem* typeItem = new QTableWidgetItem(strType);
this->setItem(nRowCount, GVL_COL_TYPE, typeItem);
typeItem->setTextAlignment(Qt::AlignCenter);
// 不可编辑
typeItem->setFlags(typeItem->flags() & (~Qt::ItemIsEditable));
// ---Value
QTableWidgetItem* valueItem = new QTableWidgetItem(strValue);
valueItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
this->setItem(nRowCount, GVL_COL_VALUE, valueItem);
// 保存一下当前输入的值
m_LastValues.push_back(strValue);
// 2022-2-22 改为仅基础模式的可编辑
if (m_gvlMode != GVL_MODE::GVL_BASIC)
{
valueItem->setFlags(valueItem->flags() & (~Qt::ItemIsEditable));
}
//// 设置单元格状态
//this->setItemOK(nRowCount, GVL_COL_VALUE);
// ---Serialized (CheckBox)
// 创建单元格的CheckBox
QCheckBox* checkSerialized = new QCheckBox();
if (bSerialized)
{
checkSerialized->setCheckState(Qt::Checked);
}
else
{
checkSerialized->setCheckState(Qt::Unchecked);
}
// 创建Widget和布局
QWidget* checkContainer = new QWidget(this);
// 设置为透明,否则看起来很奇怪(两种不同的透明效果可以任意选择)
checkContainer->setStyleSheet("background-color:transparent ");
//w->setAttribute(Qt::WA_TranslucentBackground, true);
//
// 建立水平布局
QHBoxLayout* checkLayout = new QHBoxLayout();
checkLayout->addWidget(checkSerialized);
checkLayout->setMargin(0);
checkLayout->setAlignment(checkSerialized, Qt::AlignCenter);
checkContainer->setLayout(checkLayout);
// 设置单元格为居中的Checkbox
this->setCellWidget(nRowCount, GVL_COL_SERIALIZED, checkContainer);
// 保存指针
m_cellCheckbox.insert(checkSerialized, nRowCount);
// ---Comment
if (strComment.isEmpty())
{
strComment = "Type here to input comment.";
}
QTableWidgetItem* commentItem = new QTableWidgetItem(strComment);
this->setItem(nRowCount, GVL_COL_COMMENT, commentItem);
// 设置关联信号
connect(
checkSerialized,
SIGNAL(toggled(bool)),
this,
SLOT(onTableSerializedChanged(bool))
);
connect(
this,
&QTableWidget::cellChanged,
this,
&WindowAppVariableTable::onTableCellChanged
);
// 防止消息被循环触发
this->blockSignals(false);
// 保存变量和行数的对应关系
m_VariablesRows.insert(strFullName, nRowCount);
return nRowCount;
}
///
/// 表格中添加新的一行(DB模式)
///
///
///
///
///
///
///
///
///
int WindowAppVariableTable::insertTableLine(
QString strName,
QString strFullName,
QString strType,
QString strValue,
QString strCommAddress,
VPEnum::GVL_ACCESS_MODE accessMode,
QString strComment
)
{
// 防止消息被循环触发
this->blockSignals(true);
// 获取当前行数
int nRowCount = this->rowCount();
// 添加新的一行
this->insertRow(nRowCount);
// ---Index
QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(nRowCount + 1));
indexItem->setTextAlignment(Qt::AlignCenter);
// 本列不可编辑
indexItem->setFlags(indexItem->flags() & (~Qt::ItemIsEditable));
this->setItem(nRowCount, DB_COL_INDEX, indexItem);
// ---Name
QTableWidgetItem* nameItem = new QTableWidgetItem(strName);
this->setItem(nRowCount, DB_COL_NAME, nameItem);
nameItem->setTextAlignment(Qt::AlignCenter);
// 不可编辑
nameItem->setFlags(nameItem->flags() & (~Qt::ItemIsEditable));
// ---Type
QTableWidgetItem* typeItem = new QTableWidgetItem(strType);
this->setItem(nRowCount, DB_COL_TYPE, typeItem);
typeItem->setTextAlignment(Qt::AlignCenter);
// 不可编辑
typeItem->setFlags(typeItem->flags() & (~Qt::ItemIsEditable));
// ---Value
QTableWidgetItem* valueItem = new QTableWidgetItem(strValue);
valueItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
this->setItem(nRowCount, DB_COL_VALUE, valueItem);
// 保存一下当前输入的值(为防止信号重复触发)
m_LastValues.push_back(strValue);
// ---Address
QTableWidgetItem* addressItem = new QTableWidgetItem(strCommAddress);
addressItem->setTextAlignment(Qt::AlignCenter);
this->setItem(nRowCount, DB_COL_ADDRESS, addressItem);
// ---Access
QTableWidgetItem* accessItem = new QTableWidgetItem(emGvlAccess.key((short)accessMode));
accessItem->setTextAlignment(Qt::AlignCenter);
this->setItem(nRowCount, DB_COL_ACCESS, accessItem);
// 不可编辑
accessItem->setFlags(accessItem->flags() & (~Qt::ItemIsEditable));
// ---Comment
if (strComment.isEmpty())
{
strComment = "Type here to input comment.";
}
QTableWidgetItem* commentItem = new QTableWidgetItem(strComment);
this->setItem(nRowCount, DB_COL_COMMENT, commentItem);
// 设置单元格变动的关联信号
connect(
this,
&QTableWidget::cellChanged,
this,
&WindowAppVariableTable::onTableCellChanged
);
// 防止消息被循环触发
this->blockSignals(false);
// 保存变量和行数的对应关系
m_VariablesRows.insert(strFullName, nRowCount);
return nRowCount;
}
///
/// Toolbar - MoveUp
///
void WindowAppVariableTable::onVariableMoveUp()
{
// qDebug() << "WindowAppVariableTable::onToolMoveUp";
// 获取行号
int rowIndex = this->currentRow();
if (rowIndex <= 0)
{
return;
}
int rowIndex2 = rowIndex - 1;
// 从数据结构中移动
g_pGvlManager->exchangeVariable(m_strGroup, rowIndex, rowIndex2);
// 从界面中移动
swapRows(rowIndex, rowIndex2);
// 需要移动一下焦点
this->selectRow(rowIndex2);
}
///
/// Toolbar - MoveDown
///
void WindowAppVariableTable::onVariableMoveDown()
{
// qDebug() << "WindowAppVariableTable::onToolMoveDown";
// 获取行号
int rowIndex = this->currentRow();
if (rowIndex < 0 || rowIndex == this->rowCount() - 1)
{
return;
}
int rowIndex2 = rowIndex + 1;
// 从数据结构中移动
g_pGvlManager->exchangeVariable(m_strGroup, rowIndex, rowIndex2);
// 从界面中移动
swapRows(rowIndex, rowIndex2);
// 需要移动一下焦点
this->selectRow(rowIndex2);
}
///
/// Toolbar - Delete
///
void WindowAppVariableTable::onVariableDelete()
{
// qDebug() << "WindowAppVariableTable::onToolDelete";
// g_pGvlManager->debugAllVariables();
// 获取要删除的行号
int rowIndex = this->currentRow();
if (rowIndex < 0)
{
return;
}
int nVariablesCount = g_pGvlManager->getVariablesCountByGroup(m_strGroup);
// 计算局部变量的数量
int nLocalVarSize = nVariablesCount - this->rowCount();
this->blockSignals(true);
// 首先需要检查引用计数,确定没有引用才允许删除
int nRefCount = g_pGvlManager->getRefCount(m_strGroup, rowIndex + nLocalVarSize);
if (nRefCount > 0)
{
Utility::VPCriticalMessageBox("Can't delete this variable for reference count is " + QString::number(nRefCount));
return;
}
// 提示确认
int nRet = Utility::VPQuesitonMessageBox("Are you sure to delete this variable? ");
if (nRet == QMessageBox::No)
{
return;
}
// 从数据结构中删除
g_pGvlManager->delVariable(m_strGroup, rowIndex + nLocalVarSize);
// 从界面中删除
this->removeRow(rowIndex);
// 重写删除当前行之后的Index
for (int i = rowIndex; i < this->rowCount(); i++)
{
this->item(i, GVL_COL_INDEX)->setText(QString::number(i + 1));
}
// 还需要删除对应的QCheckBox数据结构信息
QHash::iterator iter2 = m_cellCheckbox.begin();
while (iter2 != m_cellCheckbox.end())
{
if (iter2.value() == rowIndex)
{
m_cellCheckbox.erase(iter2);
break;
}
else
{
iter2++;
}
}
// 删除保存的上次变量信息
QVector::iterator iter3 = m_LastValues.begin();
m_LastValues.erase(iter3 + rowIndex);
// 还需要删除变量和行数的数据结构信息
QHash::iterator iter4 = m_VariablesRows.begin();
while (iter4 != m_VariablesRows.end())
{
if (iter4.value() == rowIndex)
{
m_VariablesRows.erase(iter4);
break;
}
else
{
iter4++;
}
}
this->blockSignals(false);
}
///
/// 调整大小的消息中改变表格栏的宽度
///
///
void WindowAppVariableTable::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
// qDebug() << "WindowAppVariableTable::resizeEvent";
int nTotalSize = this->size().width();
if (m_gvlMode != GVL_MODE::GVL_DB)
{
this->setColumnWidth(GVL_COL_INDEX, nTotalSize * 0.05);
this->setColumnWidth(GVL_COL_NAME, nTotalSize * 0.20);
this->setColumnWidth(GVL_COL_TYPE, nTotalSize * 0.15);
this->setColumnWidth(GVL_COL_VALUE, nTotalSize * 0.20);
this->setColumnWidth(GVL_COL_SERIALIZED, nTotalSize * 0.10);
this->setColumnWidth(GVL_COL_COMMENT, nTotalSize * 0.30);
}
else
{
this->setColumnWidth(DB_COL_INDEX, nTotalSize * 0.05);
this->setColumnWidth(DB_COL_NAME, nTotalSize * 0.20);
this->setColumnWidth(DB_COL_TYPE, nTotalSize * 0.10);
this->setColumnWidth(DB_COL_VALUE, nTotalSize * 0.20);
this->setColumnWidth(DB_COL_ADDRESS, nTotalSize * 0.10);
this->setColumnWidth(DB_COL_ACCESS, nTotalSize * 0.10);
this->setColumnWidth(DB_COL_COMMENT, nTotalSize * 0.25);
}
}
///
/// 当表格单元改变时
///
///
///
//int nLastrow = 0;
//int nLastCol = 0;
void WindowAppVariableTable::onTableCellChanged(int row, int col)
{
// 屏蔽Signal,防止在编辑的时候嵌套触发死循环
this->blockSignals(true);
qDebug() << "WindowAppVariableTable::onTableCellChanged (" << row << "," << col << ")";
switch (col)
{
case GVL_COL_VALUE:
{
QString strNewValue = this->item(row, GVL_COL_VALUE)->text();
QString strOldValue = m_LastValues.value(row);
// 由于本消息会多次触发,不得不在这里处理一下了
if (strNewValue == strOldValue)
{
this->blockSignals(false);
qDebug() << "WindowAppVariableTable::onTableCellChanged - updateValue duplicated.";
return;
}
bool bRet = g_pGvlManager->updateValue(m_strGroup, row, strNewValue);
// 如果值无效,则报错,并且还原用户输入
if (!bRet)
{
Utility::VPCriticalMessageBox("Invalid value at (" + QString::number(row) + "," + QString::number(col) + ")");
this->item(row, GVL_COL_VALUE)->setText(strOldValue);
}
else
{
m_LastValues[row] = strNewValue;
}
// 2022-3-8,如果本表格是DB类型变量,还需要额外通知到Dll端执行对应更新
// 将值写入到dll的工具中
if (m_gvlMode == GVL_MODE::GVL_DB)
{
// TODO:此处获取到对应的DllTool指针将最新的值写入
TOOL* pTool = g_pGvlManager->getHdwToolByDbName(m_strGroup);
if (pTool)
{
pTool->pDllPtr->updateValue(row);
}
}
//if (!bRet)
//{
// this->blockSignals(false);
// this->setItemError(row, GVL_COL_VALUE);
// return;
//}
//else
//{
// this->setItemOK(row, GVL_COL_VALUE);
//}
}
break;
// 此处还有可能是 DB_COL_ACCESS(尚未启用)
case GVL_COL_COMMENT:
{
// 修改了标准模式的注释项
if (m_gvlMode != GVL_MODE::GVL_DB)
{
QString strNewComment = this->item(row, GVL_COL_COMMENT)->text();
g_pGvlManager->updateComment(m_strGroup, row, strNewComment);
}
// 修改了DB模式的ACCESS项(尚未启用)
else
{
// 修改了DB模式的通讯地址项
if (m_gvlMode == GVL_MODE::GVL_DB)
{
QString strNewAddress = this->item(row, DB_COL_ADDRESS)->text();
g_pGvlManager->updateComment(m_strGroup, row, strNewAddress);
}
}
}
break;
case DB_COL_COMMENT:
{
QString strNewComment = this->item(row, DB_COL_COMMENT)->text();
g_pGvlManager->updateComment(m_strGroup, row, strNewComment);
}
break;
default:
qDebug() << "WindowAppVariableTable::onTableCellChanged - invalid column : " << col;
break;
}
this->blockSignals(false);
}
/////
///// 更新变量值
/////
/////
/////
//bool WindowAppVariableTable::updateValue(int row)
//{
// return false;
//}
//
//
/////
///// 更新注释
/////
/////
/////
//bool WindowAppVariableTable::updateComment(int row)
//{
// return false;
//}
///
/// 当Serialized状态发生改变时
///
///
void WindowAppVariableTable::onTableSerializedChanged(bool bChecked)
{
// 这里只能通过Sender来找到第几行的Checkbox被编辑了
QCheckBox* checkSerialized = qobject_cast(sender());
int row = m_cellCheckbox.value(checkSerialized);
qDebug() << "WindowAppVariableTable::onTableSerializedChanged [" << row << "] - " << bChecked;
g_pGvlManager->updatePersit(
m_strGroup,
row,
checkSerialized->checkState() == Qt::Checked
);
// 还需要将对应的行帮Table选中
this->selectRow(row);
//QList selItems = this->selectedItems();
//// 获取选中的行号
//int row = this->row(selItems.at(0));
//int row = this->currentItem()->row();
}
///
/// 更新表格中指定变量的值
///
///
void WindowAppVariableTable::updateTableValue(const QString& strVarFullName, const QString& strNewValue)
{
QHash::iterator iter = m_VariablesRows.find(strVarFullName);
int nRow = -1;
if (iter != m_VariablesRows.end())
{
nRow = m_VariablesRows.value(strVarFullName);
}
else
{
qDebug() << "[ERROR][WindowAppVariableTable::updateTableValue] - Invalid Variable*";
return;
}
// QString strNewValue = pVar->getValueByString();
// debugTableVariables();
this->item(nRow, GVL_COL_VALUE)->setText(strNewValue);
qDebug() << "[updateTableValue] Update tableUI - " << strVarFullName << " to " << strNewValue;
}
/////
///// 将指定的表格设置为错误状态
/////
/////
/////
//void WindowAppVariableTable::setItemError(int row, int col)
//{
// this->item(row, col)->setBackgroundColor(COLOR_ITEM_ERROR);
//}
//
//
/////
///// 将指定的表格设置为正常状态
/////
/////
/////
//void WindowAppVariableTable::setItemOK(int row, int col)
//{
// this->item(row, col)->setBackgroundColor(COLOR_ITEM_OK);
//}
///
/// 交换两行的数据
///
///
/// bSerialized
void WindowAppVariableTable::swapRows(int selectRow, int targetRow)
{
this->blockSignals(true);
QStringList selectRowLine, targetRowLine;
// 跳过Index列不需要交换
for (int i = 1; i < GVL_COLUMN_COUNT; i++)
{
if (i != GVL_COL_SERIALIZED)
{
QString strSelect = this->item(selectRow, i)->text();
QString strTarget = this->item(targetRow, i)->text();
this->item(selectRow, i)->setText(strTarget);
this->item(targetRow, i)->setText(strSelect);
}
else
{
// 交换Checkbox控件的值,这个比较麻烦一些
QWidget* selectWidget = (QWidget*)this->cellWidget(selectRow, GVL_COL_SERIALIZED);
QCheckBox* selectCheckSerialzied = qobject_cast(selectWidget->children().at(1));
bool bSelectSerialized = selectCheckSerialzied->checkState() == Qt::Checked;
QWidget* targetWidget = (QWidget*)this->cellWidget(targetRow, GVL_COL_SERIALIZED);
QCheckBox* targetCheckSerialized = qobject_cast(targetWidget->children().at(1));
bool bTargetSerialized = targetCheckSerialized->checkState() == Qt::Checked;
selectCheckSerialzied->setChecked(bTargetSerialized);
targetCheckSerialized->setChecked(bSelectSerialized);
selectRowLine.append("");
targetRowLine.append("");
}
}
//for (int i = 0; i < GVL_COLUMN_COUNT; i++)
//{
// if (i != GVL_COL_PERSISTENT)
// {
// //this->setItem(selectRow, i, new QTableWidgetItem(targetRowLine.at(i)));
// //this->setItem(targetRow, i, new QTableWidgetItem(selectRowLine.at(i)));
// }
//}
// 交换变量和行数的数据结构
QHash::iterator iter = m_VariablesRows.begin();
QString strSelectValue, strTargetValue;
while (iter != m_VariablesRows.end())
{
if (iter.value() == selectRow)
{
// m_TableVariables.erase(iter);
strSelectValue = iter.key();
}
else if (iter.value() == targetRow)
{
strTargetValue = iter.key();;
}
iter++;
}
m_VariablesRows[strSelectValue] = targetRow;
m_VariablesRows[strTargetValue] = selectRow;
this->blockSignals(false);
}