#include "WindowAppBlockStandardBase.h"
#include "WindowAppPouFrame.h"
#include "WindowAppItemInterface.h"
#include "Pou.h"
#include "DialogBlockProperty.h"
#include "WindowAppPouScene.h"
// bShowOnly 是否仅供展示使用,展示使用的话不提供右键菜单以及其他互动功能
WindowAppBlockStandardBase::WindowAppBlockStandardBase(TOOL* pTool, POU* Pou, bool bShowOnly, QGraphicsObject* parent) :
WindowAppBlockBase(pTool, Pou, bShowOnly, parent)
{
if (!bShowOnly)
{
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
}
else
{
setFlag(QGraphicsItem::ItemIsMovable, false);
}
setFlag(QGraphicsItem::ItemIsSelectable);
this->m_toolInfo = pTool;
// 创建菜单
createContextMenu();
// 更新矩形区域的尺寸
this->updateRect();
}
///////////////////////////////////////////////////////////
//// 返回功能块图形的总体矩形区域
//QRectF WIndowAppBlockStandardBase::boundingRect() const
//{
// return blockBoundingRect;
//}
/////////////////////////////////////////////////////////
//// 显示右键菜单
//void WIndowAppBlockStandardBase::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
//{
// scene()->clearSelection();
// setSelected(true);
//
// blockMenu->exec(event->screenPos());
//}
///
/// 添加接口
///
void WindowAppBlockStandardBase::addItemInterfaces()
{
// 为本Block添加新的ItemInterface
for (_INTERFACE* pInf : qAsConst(m_toolInfo->Interfaces))
{
this->addItemInterface(pInf);
}
// 更新Interface的位置(注意此处坐标系需要转换一下)
WindowAppBlockBase::updateInterfacesPostion();
}
///
/// 添加单个接口
///
///
WindowAppItemInterface* WindowAppBlockStandardBase::addItemInterface(_INTERFACE* pInfInfo)
{
WindowAppItemInterface* pNewItemInf = new WindowAppItemInterface
(
pInfInfo,
m_pPou,
this->m_toolInfo,
m_bShowOnly,
this
);
if (!m_bShowOnly)
{
// Pou中保存此接口信息
m_pPou->registerInterface(pNewItemInf, pInfInfo);
}
// 保存接口Item信息
m_itemInterfaces.append(pNewItemInf);
// 界面中添加此Interface(设置为从属关系之后,都不需要手工添加此Item了,真是方便啊)
// scene()->addItem(pNewItemInf);
return pNewItemInf;
}
///
/// 更新Block的相关位置和尺寸
///
void WindowAppBlockStandardBase::updatePosition()
{
// 更新矩形区域的尺寸
updateRect();
// 更新所有的接口
WindowAppBlockBase::updateInterfacesPostion();
//// 重绘Block
this->update();
//// 重绘所有接口
//this->redrawAllInterface();
}
///
/// 是否是StandardBase系列的Block,如果增加了新的工具类型,这里也需要补充
///
///
bool WindowAppBlockStandardBase::isStandardBasedBlock()
{
return (this->type() == ITEM_TYPE_STANDARD
|| this->type() == ITEM_TYPE_PORT
|| this->type() == ITEM_TYPE_GOTO
|| this->type() == ITEM_TYPE_PARALLEL
);
}
///
/// MoveUp
///
void WindowAppBlockStandardBase::onBlockMoveUp()
{
this->onMenuMoveUp();
}
///
/// MoveDown
///
void WindowAppBlockStandardBase::onBlockMoveDown()
{
this->onMenuMoveDown();
}
///
/// MoveFirst
///
void WindowAppBlockStandardBase::onBlockMoveFirst()
{
this->onMenuMoveFirst();
}
///
/// MoveLast
///
void WindowAppBlockStandardBase::onBlockMoveLast()
{
this->onMenuMoveLast();
}
///
/// 2022-9-28,直接给工具设置一个新的Index
///
///
void WindowAppBlockStandardBase::setToolIndex(const int& newIndex)
{
int nCurIndex = m_toolInfo->nIndex;
int nFix = newIndex - nCurIndex;
// 根据用户的索引号是增加还是减少了,进行数次前移或者后移
if (nFix > 0)
{
// 后移
for (int i = 0; i < nFix; i++)
{
this->onBlockMoveDown();
}
}
else if (nFix < 0)
{
// 前移
for (int i = 0; i < -nFix; i++)
{
this->onBlockMoveUp();
}
}
}
///
/// 更新矩形区域的尺寸
///
void WindowAppBlockStandardBase::updateRect()
{
// 计算高度
int blockHeight = TBD_BASIC_HEIGHT;
// 根据接口计算实际需要的高度
int nOutInfCount = 0;
int nInInfCount = 0;
for (_INTERFACE* pInf : m_toolInfo->Interfaces)
{
if (!m_bShowOnly && !pInf->bEnable)
{
continue;
}
// 仅绘制标准类型的端口
if (pInf->Type == INF_TYPE::INF_TYPE_EVENT
|| pInf->Type == INF_TYPE::INF_TYPE_CONTROL
)
{
continue;
}
// 2021-4-7增加,加入了接口启用与否的判断
if (pInf->Direction == INF_DIRECTION::INF_DIR_OUT)
{
nOutInfCount++;
}
else if (pInf->Direction == INF_DIRECTION::INF_DIR_IN)
{
nInInfCount++;
}
}
// 取更大的值作为整体高度
int nInfCount = nOutInfCount > nInInfCount ? nOutInfCount : nInInfCount;
// 2022-5-23,调整并排只有2个接口的情况下的高度
if (nInfCount > 1)
{
blockHeight = TBD_BASIC_HEIGHT + TBD_INF_SPACING * (nInfCount - 1) - 5;
}
// 计算宽度
int blockWidth = TBD_BASIC_WIDTH;
// TODO : 根据工具名字字符的宽度计算实际需要的宽度
// 主体矩形区域
blockRect.setRect(
-blockWidth / 2,
-blockHeight / 2,
blockWidth,
blockHeight
);
// 序号矩形区域
blockIndexRect.setRect(
blockRect.right() - TBD_INDEX_WIDTH,
blockRect.top() - TBD_INDEX_HEIGHT / 2,
TBD_INDEX_WIDTH,
TBD_INDEX_HEIGHT
);
//// 总体矩形边界
//blockBoundingRect.setRect(
// blockRect.left() - TBD_INF_LINE,
// blockRect.top() - TBD_INDEX_HEIGHT / 2,
// blockRect.width() + TBD_INF_LINE + TBD_INF_LINE,
// blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 12
//);
// 矩形边界(未计算Interface的范围)
blockBoundingRect.setRect(
blockRect.left(),
blockRect.top() - TBD_INDEX_HEIGHT,
blockRect.width() + TBD_SHADOW_COUNT * PEN_LINE_WIDTH,
blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 12
);
//// 总矩形边界(计算Interface的范围)
//blockTotalRect.setRect(
// blockRect.left() - TBD_INF_LINE * 2,
// blockRect.top() - TBD_INDEX_HEIGHT,
// blockRect.width() + TBD_INF_LINE * 4,
//
// blockRect.height() + TBD_INDEX_HEIGHT + TBD_SHADOW_COUNT * PEN_LINE_WIDTH + 15
//);
}
///
/// 添加ToolStart、ToolEnd接口,2022-8-21更新,增加了ToolEnd接口支持
///
void WindowAppBlockStandardBase::addItemToolInterfaces()
{
if (this->m_toolInfo->ToolInterfaces.size() <= 0 )
{
qDebug() << "[Error] WindowAppBlockStandardBase::addItemToolInterfaces - ignore.";
//return nullptr;
}
// 添加所有的ToolInterface
for (int i = 0; i < this->m_toolInfo->ToolInterfaces.size(); i++)
{
WindowAppItemInterface* pToolInfItem = this->addItemInterface(this->m_toolInfo->ToolInterfaces[i]);
// 更新ToolInterface的位置
QPointF pt = mapToScene(0, 0);
QRectF rcBlock = blockRect;
rcBlock.translate(pt);
pToolInfItem->updateParentRect(rcBlock);
// 更新ToolInterface的位置
pToolInfItem->updateToolInterfacePostion();
}
//// 添加ToolStart接口
//WindowAppItemInterface* pStartInfItem = this->addItemInterface(this->m_toolInfo->startInterface);
//// 更新ToolStart接口的位置
//QPointF pt = mapToScene(0, 0);
//QRectF rcBlock = blockRect;
//rcBlock.translate(pt);
//pTopInfItem->updateParentRect(rcBlock);
//// 添加ToolEnd接口
//WindowAppItemInterface* pTopInfItem = this->addItemInterface(this->m_toolInfo->startInterface);
//// 更新ToolInterface的位置
//pTopInfItem->updateToolInterfacePostion();
//return pTopInfItem;
}
/////
///// 双击弹出设置对话框
/////
/////
//void WindowAppBlockStandardBase::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
//{
// // 只有鼠标左键才响应
// if (event->button() == Qt::LeftButton && !m_bShowOnly)
// {
// // qDebug() << this->scenePos();
//
// m_pPou->ShowToolDialog(this);
// }
//}
///
/// 绘制block
///
///
///
///
void WindowAppBlockStandardBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
painter->setRenderHint(QPainter::Antialiasing, true);
WindowAppBlockBase::paint(painter, option, widget);
painter->save();
// 绘制功能块
this->DrawBlock(painter, true);
// 绘制序号
this->DrawIndex(painter);
painter->restore();
}
///
/// 绘制功能块
///
///
void WindowAppBlockStandardBase::DrawBlock(QPainter* painter, bool withToolName /*= true*/)
{
WindowAppBlockBase::DrawBlock(painter);
// 绘制功能块名字
this->DrawBlockTitle(painter, withToolName);
// 绘制断点标识
this->DrawBreakPoint(painter);
// 绘制程序指针
this->DrawPointer(painter);
}
///
/// 绘制功能块名字
///
///
/// 是否需要绘制工具基础名称
void WindowAppBlockStandardBase::DrawBlockTitle(QPainter* painter, bool withToolName /*= true*/)
{
// 实例名文字
painter->setPen(QPen(COLOR_TEXT, PEN_LINE_WIDTH));
painter->setFont(FONT_INSTANCENAME);
QRect textRect = QFontMetrics(FONT_INSTANCENAME).boundingRect(m_toolInfo->strInstanceName);
int textX = blockRect.left() + (blockRect.width() - textRect.width()) / 2;
int textY = blockRect.top() - 4;
painter->drawText(textX, textY, m_toolInfo->strInstanceName);
// 工具基础名字
if (withToolName)
{
painter->setFont(FONT_TOOLNAME);
textRect = QFontMetrics(FONT_TOOLNAME).boundingRect(m_toolInfo->strName);
textX = blockRect.left() + (blockRect.width() - textRect.width()) / 2;
textY = blockRect.top() + textRect.height() - 3;
painter->drawText(textX, textY, m_toolInfo->strName);
}
}
////////////////////////////////////////////////
// 绘制序号
void WindowAppBlockStandardBase::DrawIndex(QPainter* painter)
{
painter->setRenderHint(QPainter::Antialiasing);
// 边框
if (!this->isSelected())
{
painter->setPen(QPen(COLOR_TBD_INDEX_FRAME, PEN_LINE_WIDTH));
}
else
{
painter->setPen(QPen(COLOR_TBD_INDEX_FRAME, PEN_LINE_WIDTH_SEL));
}
// 绘制程序执行状态
this->SetExecStatus(painter);
// 绘制主体
painter->drawRoundedRect(blockIndexRect, 3, 3);
// 序号文字(最多可以容纳0-99)
painter->setPen(QPen(COLOR_TBD_INDEX_TEXT, PEN_LINE_WIDTH));
painter->setFont(FONT_INDEX);
QString strIndex = QString::number(m_toolInfo->nIndex + 1);
QRect textRect = QFontMetrics(FONT_INDEX).boundingRect(strIndex);
int textX = blockIndexRect.left() + (blockIndexRect.width() - textRect.width()) / 2;
int textY = blockIndexRect.top() + textRect.height() - 1;
// 2022-5-6 增加,如果Tool被加入了并行组,则显示一个P,不显示序号了
if (!this->m_toolInfo->isParallelSubTool())
{
painter->drawText(textX, textY, strIndex);
}
else
{
painter->drawText(textX, textY, TOOL_PARALLEL_LOGO);
}
}
///
/// 绘制断点标识
///
///
void WindowAppBlockStandardBase::DrawBreakPoint(QPainter* painter)
{
if (m_toolInfo->bEnableBreakPoint)
{
painter->setPen(QPen(Qt::red, 4, Qt::SolidLine));
painter->drawEllipse(blockRect.left() + 2, blockRect.top() + 2, 4, 4);
}
}
///
/// 绘制程序指针
///
///
void WindowAppBlockStandardBase::DrawPointer(QPainter* painter)
{
if (m_toolInfo->execParams.nStatus == VPEnum::EXEC_STATUS::Busy)
{
double x = blockRect.left() - 10.0;
double y = blockRect.top() + 4.0;
double length = 2.0;//箭头斜着的投影到线上的长度
QVector lines;
lines.append(QLineF(x, y, x + 10, y));
lines.append(QLineF(x + 5.0 + length, y + length, x + 10.0, y));
lines.append(QLineF(x + 5.0 + length, y - length, x + 10.0, y));
painter->setPen(QPen(Qt::yellow, 2, Qt::SolidLine));
painter->drawLines(lines);
}
}
///
/// 设置功能块执行状态
///
///
void WindowAppBlockStandardBase::SetExecStatus(QPainter* painter)
{
// 填充 如果工具执行失败,将标签的背景色设置成红色
switch (m_toolInfo->execParams.nRetValue)
{
case VPEnum::RETURN_VALUE::Success: painter->setBrush(COLOR_TBD_INDEX_BG); break;
case VPEnum::RETURN_VALUE::Error: painter->setBrush(COLOR_TBD_INDEX_BG_ERROR); break;
case VPEnum::RETURN_VALUE::Invalid: painter->setBrush(COLOR_TBD_INDEX_BG); break;
case VPEnum::RETURN_VALUE::Timeout: painter->setBrush(COLOR_TBD_INDEX_BG); break;
case VPEnum::RETURN_VALUE::Goto: painter->setBrush(COLOR_TBD_INDEX_BG); break;
case VPEnum::RETURN_VALUE::None: painter->setBrush(COLOR_TBD_INDEX_BG); break;
default:
painter->setBrush(COLOR_TBD_INDEX_BG);
break;
}
}
//=================================================================
//
// Menu相关
//
//=================================================================
///
/// 初始化功能块的右键菜单
///
void WindowAppBlockStandardBase::createContextMenu()
{
WindowAppBlockBase::createContextMenu();
// 硬件组态不显示右键菜单
if (m_pPou->pouName() != GROUP_NAME_HARDWARE)
{
connect(executeAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecute);
connect(executeSubAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecuteSub);
connect(executeAllAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuExecuteAll);
connect(executeBreakPoint, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuBreakPoint);
connect(moveUpAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveUp);
connect(moveDownAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveDown);
connect(moveFirstAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveFirst);
connect(moveLastAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuMoveLast);
}
connect(deleteAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuDelete);
connect(propertyAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuProperty);
connect(copyBlockAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuCopyblock);
connect(copyDataAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuCopydata);
connect(pasteAction, &QAction::triggered, this, &WindowAppBlockStandardBase::onMenuPaste);
contextMenu = new QMenu();
if (m_pPou->pouName() != GROUP_NAME_HARDWARE)
{
contextMenu->addAction(executeAction);
contextMenu->addAction(executeSubAction);
contextMenu->addAction(executeAllAction);
contextMenu->addSeparator();
contextMenu->addAction(executeBreakPoint);
contextMenu->addSeparator();
contextMenu->addAction(moveUpAction);
contextMenu->addAction(moveDownAction);
contextMenu->addAction(moveFirstAction);
contextMenu->addAction(moveLastAction);
contextMenu->addSeparator();
}
contextMenu->addAction(deleteAction);
contextMenu->addSeparator();
contextMenu->addAction(copyBlockAction);
contextMenu->addAction(copyDataAction);
contextMenu->addAction(pasteAction);
contextMenu->addSeparator();
contextMenu->addAction(propertyAction);
}
///
/// 菜单 - Execute
///
void WindowAppBlockStandardBase::onMenuExecute()
{
QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecute);
}
///
/// 菜单 - ExecuteSubsequent
///
void WindowAppBlockStandardBase::onMenuExecuteSub()
{
QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecuteSub);
}
///
/// 菜单 - ExecuteAll
///
void WindowAppBlockStandardBase::onMenuExecuteAll()
{
QFuture Future = QtConcurrent::run(this, &WindowAppBlockStandardBase::MenuExecuteAll);
}
void WindowAppBlockStandardBase::MenuExecute()
{
m_pPou->ToolExecutionDispatcher(this->m_toolInfo, TOOL_RUN_MODE::STANDALONE);
// m_pPou->ToolExecuteStandard(this->m_toolInfo);
}
///
/// - ExecuteSubsequent
///
void WindowAppBlockStandardBase::MenuExecuteSub()
{
m_pPou->ToolExecuteSub(this);
}
///
/// - ExecuteAll
///
void WindowAppBlockStandardBase::MenuExecuteAll()
{
m_pPou->ToolExecuteAll();
}
///
/// 菜单 - BreakPoint
///
void WindowAppBlockStandardBase::onMenuBreakPoint()
{
m_pPou->ToolBreakPoint(this);
this->update();
}
///
/// 菜单 - MoveUp
///
void WindowAppBlockStandardBase::onMenuMoveUp()
{
// 获取当前选中的Block
// QGraphicsItem* activeBlock = this->selectedItems().first();
m_pPou->ToolMoveUp(this);
update();
}
///
/// 菜单 - MoveDown
///
void WindowAppBlockStandardBase::onMenuMoveDown()
{
// 获取当前选中的Block
// QGraphicsItem* activeBlock = this->selectedItems().first();
m_pPou->ToolMoveDown(this);
update();
}
///
/// 菜单 - MoveFirst
///
void WindowAppBlockStandardBase::onMenuMoveFirst()
{
// 获取当前选中的Block
//QGraphicsItem* activeBlock = this->selectedItems().first();
m_pPou->ToolMoveFirst(this);
update();
}
///
/// 菜单 - MoveLast
///
void WindowAppBlockStandardBase::onMenuMoveLast()
{
// 获取当前选中的Block
//QGraphicsItem* activeBlock = this->selectedItems().first();
m_pPou->ToolMoveLast(this);
update();
}
///
/// 菜单 - Delete
///
void WindowAppBlockStandardBase::onMenuDelete()
{
// 2022-10-4,调用基类函数进行删除
WindowAppBlockBase::onDeleteItem();
//// 检查是否可以被删除
//if (!WindowAppBlockBase::couldBeDeleted())
//{
// return;
//}
//// 2022-3-5增加,如果此工具的Pou被Task选中,需要通知Task删除此工具
//if (m_pPou->isSelByTask())
//{
// WindowAppTaskView* pTaskView = g_pTaskManager->getTaskViewByName(m_pPou->m_pParentTask->strName);
// pTaskView->onDelPouTool(m_pPou, this->m_toolInfo);
//}
//// 逻辑数据删除
//m_pPou->ToolDelete(this);
//// 从界面中移除此功能块
//scene()->removeItem(this);
}
///
/// 菜单 - Property
///
void WindowAppBlockStandardBase::onMenuProperty()
{
// 显示工具属性对话框
DialogBlockProperty dlgProperty(this->m_toolInfo, m_pPou);
int res = dlgProperty.exec();
if (res != QDialog::Accepted)
{
return;
}
// 保存用户设置
BLOCK_PROPERTY settings = dlgProperty.getBlockSettings();
// 根据用户设置更新工具信息
if (!settings.strNewInstanceName.isEmpty())
{
m_pPou->setInstanceName(m_toolInfo, settings.strNewInstanceName, settings.strOldInstanceName);
}
m_pPou->setToolEnable(m_toolInfo, settings.bToolEnable);
m_pPou->setToolInfo(m_toolInfo, settings.strInfo);
m_pPou->setToolDelay(m_toolInfo, settings.nInDelay, settings.nOutDelay);
for (int i = 0; i < settings.infEnables.size(); i++)
{
// 2021-4-18 增加了判断,只处理enable发生变化的接口
if (m_toolInfo->Interfaces[i]->bEnable == settings.infEnables[i])
{
continue;
}
// 这里需要检查引用计数,不一定能成功
bool bRet = m_pPou->setInterfaceEnable(m_toolInfo, i, settings.infEnables[i]);
if (!bRet)
{
Utility::VPCriticalMessageBox(QString("Set ") + m_toolInfo->Interfaces[i]->strFullName + " failed!");
}
}
// 更新用户配置的索引号(如果需要的话)
if (this->m_toolInfo->nIndex != settings.nNewIndex && settings.nNewIndex != -1)
{
this->setToolIndex(settings.nNewIndex);
}
// 更新本工具(此处会自动完成工具重绘)
this->updatePosition();
}
///
/// 菜单 - Copy block
///
void WindowAppBlockStandardBase::onMenuCopyblock()
{
m_pPou->ToolCopyBlock(this);
}
///
/// 菜单 - Copy data
///
void WindowAppBlockStandardBase::onMenuCopydata()
{
m_pPou->ToolCopyData(this);
}
///
/// 菜单 - Paste
///
void WindowAppBlockStandardBase::onMenuPaste()
{
m_pPou->ToolPaste(this);
}