#include "WindowRuntime.h"
#include "WindowRuntimeView.h"
#include "TaskManager.h"
#include "PouManager.h"
#include "vpControls/VTableControl.h"
#include "vpControls/VPieChart.h"
#include "vpControls/VCustomPlot.h"
#include "vpControls/VImageControl.h"
#define MAINPAGE_INDEX 0
WindowRuntime::WindowRuntime(QWidget *parent)
: QMainWindow(parent)
, m_pRuntimeViews(nullptr)
{
ui.setupUi(this);
// 界面初始化
this->initUI();
// 注册本窗体
VPGlobal::Register(this);
}
WindowRuntime::~WindowRuntime()
{
}
///
/// 界面初始化
///
void WindowRuntime::initUI()
{
this->setWindowFlags(Qt::Widget);
if (1)
{
// 创建Stack式页面栈
m_pRuntimeViews = new QStackedWidget();
// 创建对应的发布页面
WindowRuntimeView* pNew = new WindowRuntimeView(m_pRuntimeViews);
m_pRuntimeViews->addWidget(pNew);
// 设置布局
QGridLayout* layout = new QGridLayout();
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_pRuntimeViews);
ui.centralWidget->setLayout(layout);
}
else
{
// TODO: RunTime 超过 UI的尺寸时,需要显示滚动条。
// TODO: RunTime 小于 UI的尺寸时,需要显示边框
//////////////////////////////////////////////////////////////////////////
QGridLayout* gridLayout = new QGridLayout(ui.centralWidget);
m_pRuntimeViews = new QStackedWidget(ui.centralWidget);
QWidget* page = new QWidget();
QGridLayout* gridLayout_3 = new QGridLayout(page);
QScrollArea* scrollArea = new QScrollArea(page);
// scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
// scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true);
QWidget* scrollAreaWidgetContents = new QWidget();
QGridLayout* gridLayout_2 = new QGridLayout(scrollAreaWidgetContents);
WindowRuntimeView* pNew = new WindowRuntimeView(scrollAreaWidgetContents); ;
gridLayout_2->addWidget(pNew, 0, 0, 1, 1);
scrollArea->setWidget(scrollAreaWidgetContents);
gridLayout_3->addWidget(scrollArea, 0, 0, 1, 1);
m_pRuntimeViews->addWidget(page);
gridLayout->addWidget(m_pRuntimeViews, 0, 0, 1, 1);
pNew->setMinimumSize(QSize(80, 80));
}
}
///
/// 发布对应的页面
///
///
/// 标记当前页面是否是主页
///
bool WindowRuntime::publishPage(WindowAppUiView* pPage, bool bMainPage /* = false */)
{
// 确保首页是一定是第一个页面
if (bMainPage)
{
if (m_pRuntimeViews!=nullptr && m_pRuntimeViews->count() > 0)
{
CRITICAL_MESSAGE("Run main page [" + pPage->m_strPageName + "] error!");
return false;
}
// 新建StackWidget
m_pRuntimeViews = new QStackedWidget();
ui.centralWidget->layout()->addWidget(m_pRuntimeViews);
}
// 创建新的Runtime页面添加到Stack中
WindowRuntimeView* pNewView = new WindowRuntimeView(m_pRuntimeViews);
m_pRuntimeViews->addWidget(pNewView);
// 保存页面序号
m_AllViews.insert(pPage->m_strPageName, m_pRuntimeViews->count() - 1);
// 发布本页面中的所有控件
// 此处需要检查是否所有的控件都拷贝成功
bool bRet = pNewView->copyFrom(pPage);
Q_UNUSED(bRet);
return true;
}
///
/// 启动所有的UI界面(目前先只支持启动所有页面的方式)
///
bool WindowRuntime::publishAllPages(
WindowAppUiView* pMainPage,
QMap allPages
)
{
// 首先执行数据结构重置
this->reset();
// 首先发布主页
bool bRet = publishPage(pMainPage, true);
// 如果首页发布失败,则退出
if (!bRet)
{
return false;
}
// 根据每一个 WindowAppUiView 生成对应的页面,并且把所有的控件都分布上去
QMapIterator it(allPages);
while (it.hasNext())
{
WindowAppUiView* pPage = it.next().value();
if (pPage != pMainPage)
{
// 其余子页面暂时不检查返回值,如果发布失败则继续发布下一个页面
bRet = publishPage(pPage);
}
}
// 页面全部发布完毕后,默认显示主页
if (m_pRuntimeViews!=nullptr &&
m_pRuntimeViews->count() > 0)
{
m_pRuntimeViews->setCurrentIndex(MAINPAGE_INDEX);
}
return true;
}
///
/// 执行指令
///
/// 命令名字
/// 命令参数
///
bool WindowRuntime::runCmd(const QString& strCmd, const QString& strParam /*= ""*/)
{
// 启动所有Task的执行
if (strCmd == SYS_CMD_TASK_RUN)
{
qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUN;
g_pTaskManager->executeAllTasks(false);
}
// 启动所有Task的执行一次
else if (strCmd == SYS_CMD_TASK_RUNONCE)
{
qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUNONCE;
g_pTaskManager->executeAllTasks(true);
}
// 停止所有任务
else if (strCmd == SYS_CMD_TASK_STOP)
{
qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_STOP;
g_pTaskManager->stopAllTask(false);
}
// 切换UI
else if (strCmd == SYS_CMD_UI_SWITCH)
{
qDebug() << "[Command] runCmd - " << SYS_CMD_UI_SWITCH << " - " << strParam;
g_pRuntime->switchToPage(strParam);
}
// 不应该执行到这里
else
{
qWarning() << "SystemCommand::runCmd - unknown command : " << strCmd;
return false;
}
return true;
}
///
/// 执行Dll中的Tool Interface
///
///
///
///
///
bool WindowRuntime::runDllInterface(
const QString& strPouName,
const QString& strToolName,
const QString& strInfName,
VALUE_TYPE controlType
)
{
// 首先根据名字找到Pou
POU* pPou = g_pPouManager->getPouByName(strPouName);
if (pPou == nullptr)
{
qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid pou name : " << strPouName;
return false;
}
// 然后找到对应的接口
QString strInfFullname = strToolName + "." + strInfName;
_INTERFACE* pInf = pPou->GetInterface(strInfFullname);
if (pInf == nullptr)
{
qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid interface name : " << strInfFullname;
return false;
}
// 根据不同的Runtime控件类型进行不同的处理
if (controlType == VALUE_TYPE::Control_Button)
{
// 获取dll中导出的控件指针
QPushButton* pInfButton = (QPushButton*)pInf->getValuePtr();
// 发送clicked信号
emit pInfButton->clicked();
return true;
}
else
{
qWarning() << "[Error] in WindowRuntime::runDllInterface() - Control type is not support : " << static_cast(controlType);
return false;
}
}
///
/// 系统命令,切换到指定页面
///
/// 2121
///
bool WindowRuntime::switchToPage(const QString& strPageName)
{
// 执行界面的切换
if (m_AllViews.contains(strPageName))
{
int nPageIndex = m_AllViews[strPageName];
// 找到指定页面,并切换
m_pRuntimeViews->setCurrentIndex(nPageIndex);
qDebug() << "WindowRuntime::switchToPage() - " << strPageName << " index: " << nPageIndex;
return true;
}
// Error: 不应该执行到这里
else
{
qDebug() << "[Error] in WindowRuntime::switchToPage() - " << strPageName << ", but can;t find this page";
return false;
}
}
//========================================================================
//
// 变量同步相关代码
//
//========================================================================
///
/// 接收来自变量到复杂控件单向同步的Event
/// 备注:复杂控件是根据索引值绑定变量主动发起的event来触发更新的
///
///
void WindowRuntime::customEvent(QEvent* event)
{
// 如果是数值同步消息
if (event->type() == VALUE_EVENT_TYPEID)
{
qDebug() << "WindowRuntime::customEvent - VALUE_EVENT_TYPEID";
SyncValueEvent* pValueEvent = dynamic_cast (event);
// 取出参数
QList syncValues = pValueEvent->getSyncValues();
for (VARIABLE* syncVal : syncValues)
{
// 从变量中同步
this->syncFromComplexSource(syncVal);
}
}
else
{
QEvent::Type type = event->type();
qWarning() << "WindowRuntime::customEvent Type:" <
/// 添加一个新的索引和控件对应关系
///
///
///
void WindowRuntime::registerNewIndex(VARIABLE* pIndex, QWidget* pControl)
{
if (pIndex == nullptr || pControl == nullptr)
{
return;
}
// 为接口设置索引标识
pIndex->bComplexLinkIndex = true;
// 加入数据结构中
m_IndexToComplexControls.insertMulti(pIndex, pControl);
}
///
/// 为控件添加一个变量
///
///
///
void WindowRuntime::registerNewVariable(QWidget* pControl, const QString& strPropertyName, const VARIABLE* pVariable)
{
if (pVariable == nullptr || pControl == nullptr)
{
return;
}
RUNTIME_SYNC_VAR newVar(strPropertyName, pVariable);
// 如果找到了本Control对应的变量,则直接添加变量
if (m_ComplexControlToVariables.contains(pControl))
{
RUNTIME_SYNC_VARS& vars = m_ComplexControlToVariables[pControl];
vars.push_back(newVar);
}
// 如果没有找到,则新建此变量
else
{
RUNTIME_SYNC_VARS vars;
vars.push_back(newVar);
m_ComplexControlToVariables.insert(pControl, vars);
}
}
///
/// 释放对应控件关系
///
///
void WindowRuntime::releaseControl(QWidget* pWidget)
{
m_ComplexControlToVariables.remove(pWidget);
// QMutableHashIterator iter(m_IndexToComplexControls);
// while (iter.hasNext())
// {
// // 更新了删除元素的方式
// const QList& listWidgets = m_IndexToComplexControls.values(iter.next().key());
for (const VARIABLE* pVar : m_IndexToComplexControls.uniqueKeys())
{
// 更新了删除元素的方式
const QList& listWidgets = m_IndexToComplexControls.values(pVar);
for (int i = 0; i < listWidgets.count(); i++)
{
if (listWidgets.at(i) == pWidget)
{
// m_IndexToComplexControls.remove(iter.key(), pWidget);
m_IndexToComplexControls.remove(pVar, pWidget);
return;
}
}
}
}
///
/// 从复杂控件的触发源头同步(一般都是Pou中的Execute,每轮执行会触发更新一遍Runtime)
///
///
void WindowRuntime::syncFromComplexSource(const VARIABLE* syncVal)
{
// 如果本轮需要同步的Value的不是索引所在的pou,那么就不更新,等着索引所在的pou执行后再统一更新
// (MEMO:这个判断放在Pou中了,只有索引变量才会被推送过来)
// 所以这个判断不可能命中
if (syncVal == nullptr || !syncVal->bComplexLinkIndex)
{
return;
}
// 如果本轮执行的是索引所在的pou则更新其他所有pou中的关联值
// 首先找到这个索引变量对应的控件指针
if (m_IndexToComplexControls.contains(syncVal))
{
// 2021-12-28 修改,此处改为一个索引源触发多个控件刷新
QList pControls = m_IndexToComplexControls.values(syncVal);
for (QWidget* pControl : pControls)
{
// 根据控件类型的不同,单独进行处理
QString strClassName = pControl->metaObject()->className();
// 如果是Table类型
if (strClassName == CLASS_NAME_TABLECONTROL)
{
// 传递Table指针以及对应的列索引数据
int nRowIndex = syncVal->getValueString().toInt();
this->syncToTableControl(pControl, nRowIndex);
}
// 如果是VCustomPlot类型
else if (strClassName == CLASS_NAME_CUSTOMPLOT)
{
// 传递VCustomPlot指针以及对应的分块索引数据
int nRowIndex = syncVal->getValueString().toInt();
this->syncToCustomPlot(pControl, nRowIndex);
}
// 如果是Pie类型
else if (strClassName == CLASS_NAME_PIECHART)
{
// 传递Pie指针以及对应的分块索引数据
int nRowIndex = syncVal->getValueString().toInt();
this->syncToPieChart(pControl, nRowIndex);
}
// 如果是Image类型
else if (strClassName == CLASS_NAME_IMAGECONTROL)
{
this->syncToImageControl(pControl);
}
}
}
// 不应该走到这里
else
{
qDebug() << "WindowRuntime::syncFromComplexSource - Critical error : can't find correct relation from syncvalue["
<< syncVal->strFullName << "].";
}
}
///
/// 同步到Table控件中
///
///
void WindowRuntime::syncToTableControl(QWidget* pControl, int nRowIndex)
{
VTableControl* pTableWidget = qobject_cast(pControl);
// 如果给定的Index数值超出了Table的最大范围,则忽略
if (nRowIndex >= pTableWidget->rowCount())
{
//qDebug() << "WindowRuntime::syncToTableControl - nRowIndex > table row count, ignore : " << nRowIndex;
nRowIndex = 0;
//return;
}
// 找到Table对应的各个数值信息
if (m_ComplexControlToVariables.contains(pControl))
{
RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
// 刷新对应的表格
// this->updateTableControl(pTableWidget, vars, nRowIndex);
// 刷新这一行
pTableWidget->updateRowFromVariables(sync_vars, nRowIndex);
}
// 不应该走到这里
else
{
qDebug() << "WindowRuntime::syncToTableControl - Critical error : can't find correct relation from m_ComplexControlToVariables.";
}
}
/////
///// 刷新Table控件中的值
/////
/////
/////
//void WindowRuntime::updateTableControl(QTableWidget* pTableWidget, const RUNTIME_SYNC_VARS& vars, int nRowIndex)
//{
// // 将最新的值都更新到Table控件中(一次更新一整列)
// int nColCount = pTableWidget->columnCount();
//
// for (int i = 0; i < nColCount; i++)
// {
// QString strValue = vars[i]->getValueString();
//
// pTableWidget->setItem(
// nRowIndex,
// i,
// new QTableWidgetItem(strValue)
// );
// }
//}
///
/// 同步到CustomPlot控件中
///
///
///
void WindowRuntime::syncToCustomPlot(QWidget* pControl, int nSliceIndex)
{
Q_UNUSED(nSliceIndex);
VCustomPlot* pCustomPlot = qobject_cast(pControl);
if (pCustomPlot != nullptr)
{
// 找到对应的各个数值信息
if (m_ComplexControlToVariables.contains(pControl))
{
RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
for (int i = 0; i < sync_vars.size(); i++)
{
int nValue = sync_vars[i].pVariable->getValueString().toInt();
// 防止数据越界
if (pCustomPlot->getCustomPlotCount() > i)
{
pCustomPlot->updateCustomPlotValue(nValue, i);
}
}
}
// 不应该走到这里
else
{
qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables.";
}
}
}
///
/// 同步到Pie控件中
///
///
///
void WindowRuntime::syncToPieChart(QWidget* pControl, int nSliceIndex)
{
Q_UNUSED(nSliceIndex);
VPieChart* pPieChart = qobject_cast(pControl);
if (pPieChart != nullptr)
{
// 找到对应的各个数值信息
if (m_ComplexControlToVariables.contains(pControl))
{
RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
for (int i = 0; i < sync_vars.size(); i++)
{
int nValue = sync_vars[i].pVariable->getValueString().toInt();
// 防止数据越界
if (pPieChart->getSliceCount() > i )
{
pPieChart->updateSliceValue(nValue, i);
}
}
}
// 不应该走到这里
else
{
qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables.";
}
}
}
///
/// 同步到Image控件中
///
///
void WindowRuntime::syncToImageControl(QWidget* pControl)
{
VImageControl* pImageControl = qobject_cast(pControl);
// 找到对应的各个数值信息
if (m_ComplexControlToVariables.contains(pControl))
{
RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
// 刷新本图像
pImageControl->updateImageFromVariables(sync_vars);
}
// 不应该走到这里
else
{
qDebug() << "WindowRuntime::syncToImageControl - Critical error : can't find correct relation from m_ComplexControlToVariables.";
}
}
///
/// 重置所有数据结构,准备执行新的发布动作
///
void WindowRuntime::reset()
{
// 首先清空当前所有页面
RELEASE(m_pRuntimeViews);
m_AllViews.clear();
m_IndexToComplexControls.clear();
m_ComplexControlToVariables.clear();
}