DialogDataLink.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. #include "DialogDataLink.h"
  2. #include "PouManager.h"
  3. #include "UiManager.h"
  4. #include "GvlManager.h"
  5. #include "vpControls/VControlObject.h"
  6. #include "vpControls/VImageControl.h"
  7. #include "vpControls/VPieChart.h"
  8. //#include "vpControls/VWaveChart.h"
  9. #include "vpControls/VTableControl.h"
  10. DialogDataLink::DialogDataLink(
  11. const QString& strPropertyName,
  12. VControlObject* pCurrentObject,
  13. const DataLink& value,
  14. QWidget *parent
  15. )
  16. : m_strPropertyName(strPropertyName)
  17. , m_strPropertyShortName(strPropertyName)
  18. , m_pControlObject(pCurrentObject)
  19. , QDialog(parent)
  20. , m_DataLink(value)
  21. {
  22. ui.setupUi(this);
  23. // 特殊需要额外处理的属性名称
  24. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_MAINLINK_NAME, VALUE_TYPE::Type_HImage);
  25. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_LINK1_NAME, VALUE_TYPE::Type_HObject);
  26. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_LINK3_NAME, VALUE_TYPE::Type_HTuple);
  27. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_LINK5_NAME, VALUE_TYPE::Type_HObject);
  28. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_LINK7_NAME, VALUE_TYPE::Type_String);
  29. m_propertiesNameToType.insert(IMAGE_PROPERTY_EX_LINK8_NAME, VALUE_TYPE::Type_String);
  30. // 把属性名字后面的数字去掉便于匹配
  31. for (int i = m_strPropertyShortName.size() - 1; i >= 0; i--)
  32. {
  33. QChar c = m_strPropertyShortName[i];
  34. if (c >= '0' && c <= '9')
  35. {
  36. m_strPropertyShortName.remove(c);
  37. }
  38. else
  39. {
  40. break;
  41. }
  42. }
  43. // 对话框初始化
  44. initUI();
  45. // qDebug() << "DialogDataLink::DialogDataLink() - bind m_pControlObject->m_pWidget:" << m_pControlObject->m_pWidget;
  46. }
  47. DialogDataLink::~DialogDataLink()
  48. {
  49. }
  50. /// <summary>
  51. /// 对话框初始化
  52. /// </summary>
  53. void DialogDataLink::initUI()
  54. {
  55. this->setWindowTitle(("Data Link"));
  56. this->setAttribute(Qt::WA_QuitOnClose);
  57. this->setWindowModality(Qt::ApplicationModal);
  58. // this->setFocusPolicy(Qt::StrongFocus);
  59. // 去掉帮助提示框
  60. this->setWindowFlags(this->windowFlags() & (~Qt::WindowContextHelpButtonHint));
  61. // 根据不同的控件类型
  62. this->initComboGroup();
  63. // Tree
  64. // 1列
  65. ui.treeTool->setColumnCount(1);
  66. // 隐藏表头
  67. ui.treeTool->setHeaderHidden(true);
  68. // 显示虚线
  69. ui.treeTool->setStyle(QStyleFactory::create("windows"));
  70. // 槽函数
  71. connect(ui.selectButton, SIGNAL(clicked()), this, SLOT(onButtonSelectClicked()));
  72. connect(ui.clearButton, SIGNAL(clicked()), this, SLOT(onButtonClearClicked()));
  73. connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
  74. connect(ui.comboValueGroup, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboGroupChanged(int)));
  75. // 设置固定窗体大小
  76. this->setFixedSize(484, 487);
  77. }
  78. /// <summary>
  79. /// 初始化数据链接分组
  80. /// </summary>
  81. void DialogDataLink::initComboGroup()
  82. {
  83. // 首先处理特殊类型
  84. if (m_propertiesNameToType.contains(m_strPropertyShortName))
  85. {
  86. this->initComboGroupByPropertyName();
  87. }
  88. // 2022-5-22 添加字符类型
  89. else if ((m_pControlObject->m_Type == VALUE_TYPE::Control_Image)
  90. && m_strPropertyShortName == IMAGE_PROPERTY_EX_LINK6_NAME)
  91. {
  92. this->initComboGroupByValue();
  93. }
  94. // 如果是Button类型
  95. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Button)
  96. {
  97. this->initComboGroupByButton();
  98. }
  99. // 如果是Value类型、或者复杂数值类型,都是绑定数值变量的
  100. // TODO 2021-12-7: 此处应该为Complex类型专门设计一个初始化函数,因为需要的变量类型还是不大一样的
  101. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Value
  102. || m_pControlObject->m_Type == VALUE_TYPE::Control_Result
  103. || m_pControlObject->isComplexControl()
  104. )
  105. {
  106. this->initComboGroupByValue();
  107. }
  108. // 如果是Label 控件、GroupBox控件,不链接任何接口
  109. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Label
  110. || m_pControlObject->m_Type == VALUE_TYPE::Control_Groupbox)
  111. {
  112. return;
  113. }
  114. // 如果是其他控件
  115. else
  116. {
  117. this->initComboGroupByOther();
  118. }
  119. // 默认选择ComboBox中的第一项
  120. ui.comboValueGroup->setCurrentIndex(0);
  121. this->onComboGroupChanged(0);
  122. }
  123. /// <summary>
  124. /// 按照一些特殊的属性名称来分组(例如Image中的图像链接、HObject、HTuple链接等等)
  125. /// </summary>
  126. void DialogDataLink::initComboGroupByPropertyName()
  127. {
  128. QMap<QString, POU*>& allPous = g_pPouManager->getAllPous();
  129. // 遍历所有的Pou信息
  130. QMapIterator<QString, POU*> it(allPous);
  131. // 找出控件类型相同的输出接口,就把这个Pou分组添加进来
  132. while (it.hasNext())
  133. {
  134. if (it.next().value()->containInterface(
  135. m_propertiesNameToType[m_strPropertyShortName],
  136. INF_DIRECTION::INF_DIR_OUT)
  137. )
  138. {
  139. // 添加适配的Pou分组
  140. ui.comboValueGroup->addItem(it.key());
  141. }
  142. }
  143. // // Pou 以及Pou 局部变量,分两个组(含硬件组态) -------------------
  144. //
  145. //// 添加所有tool数量>0的Pou
  146. // QMap<QString, POU*>& allPous = g_pPouManager->getAllPous();
  147. //
  148. // // 遍历所有的Pou信息
  149. // QMapIterator<QString, POU*> it(allPous);
  150. //
  151. // while (it.hasNext())
  152. // {
  153. // QString pouName = it.next().key();
  154. //
  155. // // Tool数量>0的添加进来
  156. // if (it.value()->GetAllStandardTools().size() > 0)
  157. // {
  158. // // 添加适配的Pou分组
  159. // ui.comboValueGroup->addItem(pouName);
  160. // }
  161. //
  162. // // 如果局部变量数量 > 0的也添进来
  163. // GVL* pVar = g_pVariablesManager->getVariablesByGroup(pouName);
  164. // if (pVar != nullptr)
  165. // {
  166. // // 添加适配的Pou.Varables分组
  167. // ui.comboValueGroup->addItem(pouName + VAR_SUFFIX);
  168. // }
  169. // }
  170. //
  171. // //// 硬件Pou和局部变量 -------------------------------------
  172. //
  173. // //// 硬件Pou
  174. // //POU* pHdPou = g_pPouManager->getPouByName(CATEGORY_TOOL_HARDWARE);
  175. // //if (pHdPou != nullptr && pHdPou->GetAllStandardTools().size() > 0)
  176. // //{
  177. // // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE);
  178. // //}
  179. //
  180. // //GVL* pHdVarable = g_pVariablesManager->getVariablesByGroup(CATEGORY_TOOL_HARDWARE);
  181. // //// 如果硬件局部变量的数量>0,那么也添加进来
  182. // //if (pHdVarable != nullptr
  183. // // && pHdVarable->Variables.size() > 0)
  184. // //{
  185. // // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE + VAR_SUFFIX);
  186. // //}
  187. //
  188. // // 全局变量 -----------------------------------------
  189. //
  190. // ALL_VARIABLES* pAllVariables = g_pVariablesManager->getAllVariables();
  191. // QHashIterator<QString, GVL*> it2(*pAllVariables);
  192. // while (it2.hasNext())
  193. // {
  194. // const GVL* pGvl = it2.next().value();
  195. // // 如果全局变量的数量>0
  196. // if (pGvl->Type == TOOL_TYPE::TOOL_TYPE_GLOBAL_VARIABLE
  197. // && pGvl->Variables.size() > 0
  198. // )
  199. // {
  200. // ui.comboValueGroup->addItem(it2.key());
  201. // }
  202. // }
  203. }
  204. /// <summary>
  205. /// Button 控件
  206. /// 1、链接到系统功能上(SysRun、SysRunOnce、SysStop)
  207. /// 2、链接到输入型的Button控件上
  208. /// 3、链接到任意工具上(点击按钮的时候,等同于双击工具的功能块)
  209. /// </summary>
  210. void DialogDataLink::initComboGroupByButton()
  211. {
  212. // 添加系统命令分组
  213. ui.comboValueGroup->addItem(SYS_CMD_GROUP_NAME);
  214. // 添加所有的Pou中的所有工具
  215. // 获取所有Pou
  216. QMap<QString, POU*>& allPous = g_pPouManager->getAllPous();
  217. // 遍历所有的Pou信息
  218. QMapIterator<QString, POU*> it(allPous);
  219. // 只要Tool数量>0的就添加进来
  220. while (it.hasNext())
  221. {
  222. if (it.next().value()->GetAllStandardTools().size()>0 )
  223. {
  224. // 添加适配的Pou分组
  225. ui.comboValueGroup->addItem(it.key());
  226. }
  227. }
  228. }
  229. /// <summary>
  230. /// 按ValueControl类型初始化分组
  231. /// 1、链接到输出型的任意数据类型端口上 (单向同步,用于任意输出型变量的String化展示),一对多
  232. /// 同步规则:
  233. ///(1)tool变动时,向UI和Runtime所有链接的控件实时同步;
  234. ///(2)UI变动时,不做任何同步动作;
  235. /// (3) runtime变动时,不做任何同步动作;
  236. /// 2、链接到输入型的基础数据类型端口上 (单向同步,RunTime Edit->工具)一对一
  237. /// 同步规则:
  238. ///(1)tool变动时,UI和Runtime 不做任何动作;
  239. ///(2)UI变动时,同步到Runtime和tool中;
  240. ///(3)Runtime变动时,同步到UI和tool中。
  241. /// 注意本数据连接同样作为端口的连接,需要引用计数 + 1
  242. /// 3、该控件需要链接到任意全局变量和硬件组态的局部变量
  243. /// 4、 不允许链接到控件类型端口(控件类型端口同样也以字符串的形式展示)
  244. /// </summary>
  245. void DialogDataLink::initComboGroupByValue()
  246. {
  247. // Pou 以及Pou 局部变量,分两个组(含硬件组态) -------------------
  248. // 添加所有tool数量>0的Pou
  249. QMap<QString, POU*>& allPous = g_pPouManager->getAllPous();
  250. // 遍历所有的Pou信息
  251. QMapIterator<QString, POU*> it(allPous);
  252. while (it.hasNext())
  253. {
  254. QString pouName = it.next().key();
  255. // Tool数量>0的添加进来
  256. if (it.value()->GetAllStandardTools().size() > 0)
  257. {
  258. // 添加适配的Pou分组
  259. ui.comboValueGroup->addItem(pouName);
  260. }
  261. // 如果局部变量数量 > 0的也添进来
  262. GVL* pVar = g_pGvlManager->getGvl(pouName);
  263. if (pVar != nullptr && pouName != GROUP_NAME_HARDWARE)
  264. {
  265. // 添加适配的Pou.Varables分组
  266. ui.comboValueGroup->addItem(pouName + VAR_SUFFIX);
  267. }
  268. }
  269. //// 硬件Pou和局部变量 -------------------------------------
  270. //// 硬件Pou
  271. //POU* pHdPou = g_pPouManager->getPouByName(CATEGORY_TOOL_HARDWARE);
  272. //if (pHdPou != nullptr && pHdPou->GetAllStandardTools().size() > 0)
  273. //{
  274. // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE);
  275. //}
  276. //GVL* pHdVarable = g_pVariablesManager->getVariablesByGroup(CATEGORY_TOOL_HARDWARE);
  277. //// 如果硬件局部变量的数量>0,那么也添加进来
  278. //if (pHdVarable != nullptr
  279. // && pHdVarable->Variables.size() > 0)
  280. //{
  281. // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE + VAR_SUFFIX);
  282. //}
  283. // 全局变量 -----------------------------------------
  284. GVLS* pAllVariables = g_pGvlManager->getAllGvls();
  285. QMapIterator<QString, GVL*> it2(*pAllVariables);
  286. while (it2.hasNext())
  287. {
  288. const GVL* pGvl = it2.next().value();
  289. // 不加判断,偶尔会崩溃 2022-02-12
  290. if (pGvl != nullptr && !pGvl->isDefaultValueGroup())
  291. {
  292. // 如果全局变量的数量>0
  293. if (pGvl->Type == TOOL_TYPE::TOOL_TYPE_GLOBAL_VARIABLE
  294. && pGvl->Variables.size() > 0
  295. )
  296. {
  297. ui.comboValueGroup->addItem(it2.key());
  298. }
  299. }
  300. }
  301. }
  302. /// <summary>
  303. /// Edit、RadioBox、ListBox、ComboBox、CheckBox控件
  304. /// 1、链接到输入型号的控件端口上,(不需要实现)
  305. /// 2、链接到输出型的控件端口上(三向同步),一对一
  306. /// 同步规则:
  307. ///(1)tool变动时,向UI和Runtime实时同步;
  308. /// (2) UI变动时,向tool和Runtime实时同步;
  309. /// (3) Runtime变动时,向tool和UI实时同步。
  310. /// 3、不允许链接到非控件型端口
  311. /// </summary>
  312. void DialogDataLink::initComboGroupByOther()
  313. {
  314. QMap<QString, POU*>& allPous = g_pPouManager->getAllPous();
  315. // 遍历所有的Pou信息
  316. QMapIterator<QString, POU*> it(allPous);
  317. // 找出控件类型相同的输出接口,就把这个Pou分组添加进来
  318. while (it.hasNext())
  319. {
  320. if (it.next().value()->containInterface(m_pControlObject->m_Type, INF_DIRECTION::INF_DIR_OUT))
  321. {
  322. // 添加适配的Pou分组
  323. ui.comboValueGroup->addItem(it.key());
  324. }
  325. }
  326. // //// 硬件Pou和局部变量 -------------------------------------
  327. //
  328. // //// 硬件Pou
  329. // //POU* pHdPou = g_pPouManager->getPouByName(CATEGORY_TOOL_HARDWARE);
  330. // //if (pHdPou != nullptr && pHdPou->GetAllStandardTools().size() > 0)
  331. // //{
  332. // // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE);
  333. // //}
  334. //
  335. // //GVL* pHdVarable = g_pVariablesManager->getVariablesByGroup(CATEGORY_TOOL_HARDWARE);
  336. // //// 如果硬件局部变量的数量>0,那么也添加进来
  337. // //if (pHdVarable != nullptr
  338. // // && pHdVarable->Variables.size() > 0)
  339. // //{
  340. // // ui.comboValueGroup->addItem(CATEGORY_TOOL_HARDWARE + VAR_SUFFIX);
  341. // //}
  342. //
  343. // // 全局变量 -----------------------------------------
  344. //
  345. // ALL_VARIABLES* pAllVariables = g_pVariablesManager->getAllVariables();
  346. // QHashIterator<QString, GVL*> it2(*pAllVariables);
  347. // while (it2.hasNext())q
  348. // {
  349. // const GVL* pGvl = it2.next().value();
  350. // // 如果全局变量的数量>0
  351. // if (pGvl->Type == TOOL_TYPE::TOOL_TYPE_GLOBAL_VARIABLE
  352. // && pGvl->Variables.size() > 0
  353. // )
  354. // {
  355. // ui.comboValueGroup->addItem(it2.key());
  356. // }
  357. // }
  358. }
  359. /// <summary>
  360. /// Combo框选择变更时,需要切换对应的变量列表
  361. /// </summary>
  362. /// <param name="nIndex"></param>
  363. void DialogDataLink::onComboGroupChanged(int nIndex)
  364. {
  365. Q_UNUSED(nIndex);
  366. // 先将当前的树形控件及对应数据结构全部清空
  367. ui.treeTool->clear();
  368. // 获取当前选中的分组名称
  369. QString strGroup = ui.comboValueGroup->currentText();
  370. // 如果当前选择的是系统命令组,则显示对应的系统命令
  371. if (strGroup == SYS_CMD_GROUP_NAME)
  372. {
  373. AddSystemCmdToTree();
  374. }
  375. // 如果是Pou分组
  376. else if(g_pPouManager->isPou(strGroup))
  377. {
  378. AddPouToolsToTree(strGroup);
  379. }
  380. // 如果是全局变量分组
  381. else if (g_pGvlManager->isGlobalGvl(strGroup))
  382. {
  383. AddPouVariablesToTree(strGroup);
  384. }
  385. // 如果是Pou局部变量分组
  386. else if (strGroup.contains(VAR_SUFFIX))
  387. {
  388. // 去掉后缀找到真正的变量分组名称
  389. strGroup.remove(VAR_SUFFIX);
  390. AddPouVariablesToTree(strGroup);
  391. }
  392. // 无效分组(不应该执行到这里)
  393. else if(!strGroup.isEmpty())
  394. {
  395. qWarning() << "DialogDataLink - Invalid value group[" << strGroup << "].";
  396. }
  397. // 将树形结构展开
  398. ui.treeTool->expandAll();
  399. }
  400. /// <summary>
  401. /// 添加系统命令
  402. /// </summary>
  403. void DialogDataLink::AddSystemCmdToTree()
  404. {
  405. // 首先添加几个Task相关命令
  406. QTreeWidgetItem* newItem = new QTreeWidgetItem(QStringList(QString(SYS_CMD_TASK_RUN)));
  407. newItem->setIcon(0, QIcon("./image/gvl_group_tree_item.png"));
  408. ui.treeTool->addTopLevelItem(newItem);
  409. newItem = new QTreeWidgetItem(QStringList(QString(SYS_CMD_TASK_RUNONCE)));
  410. newItem->setIcon(0, QIcon("./image/gvl_group_tree_item.png"));
  411. ui.treeTool->addTopLevelItem(newItem);
  412. newItem = new QTreeWidgetItem(QStringList(QString(SYS_CMD_TASK_STOP)));
  413. newItem->setIcon(0, QIcon("./image/gvl_group_tree_item.png"));
  414. ui.treeTool->addTopLevelItem(newItem);
  415. // 然后添加可以切换的界面
  416. newItem = new QTreeWidgetItem(QStringList(QString(SYS_CMD_UI_SWITCH)));
  417. newItem->setIcon(0, QIcon("./image/gvl_group_tree_item.png"));
  418. ui.treeTool->addTopLevelItem(newItem);
  419. // 添加当前所有的设计页面信息
  420. QStringList uiLIst = g_pUiManager->getAllUiNames();
  421. for (QString strName : uiLIst)
  422. {
  423. QTreeWidgetItem* uiItem = new QTreeWidgetItem(newItem, QStringList(strName));
  424. uiItem->setIcon(0, QIcon(":/image/Input.png"));
  425. newItem->addChild(uiItem);
  426. }
  427. }
  428. /// <summary>
  429. /// 添加选中的Pou Tool
  430. /// </summary>
  431. /// <param name="strGroup"></param>
  432. void DialogDataLink::AddPouToolsToTree(const QString& strGroup)
  433. {
  434. // 添加兼容的Pou工具到界面中
  435. POU* pPou = g_pPouManager->getPouByName(strGroup);
  436. // 2022-1-16,为特殊的字段进行特殊处理
  437. if (m_propertiesNameToType.contains(m_strPropertyShortName))
  438. {
  439. this->AddPouToolsByPropertyName(pPou);
  440. }
  441. // 如果是Button类型
  442. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Button)
  443. {
  444. this->AddPouToolsByButton(pPou);
  445. }
  446. // 如果是Value类型
  447. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Value)
  448. {
  449. this->AddPouToolsByValue(pPou);
  450. }
  451. // 如果是Value类型
  452. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Result)
  453. {
  454. this->AddPouToolsByValue(pPou);
  455. }
  456. // 如果是Image类型
  457. else if ((m_pControlObject->m_Type == VALUE_TYPE::Control_Image)
  458. && (m_strPropertyShortName == IMAGE_PROPERTY_EX_LINK6_NAME)
  459. )
  460. {
  461. this->AddPouToolsByValue(pPou);
  462. }
  463. // 如果是复杂控件类型
  464. else if (m_pControlObject->isComplexControl())
  465. {
  466. this->AddPouToolsByComplexValue(pPou);
  467. }
  468. // 如果是Label 控件、GroupBox控件,不添加任何信息(应该不会走到这里)
  469. else if (m_pControlObject->m_Type == VALUE_TYPE::Control_Label
  470. || m_pControlObject->m_Type == VALUE_TYPE::Control_Groupbox)
  471. {
  472. return;
  473. }
  474. // 如果是其他控件
  475. else
  476. {
  477. this->AddPouToolsByOther(pPou);
  478. }
  479. }
  480. /// <summary>
  481. /// 按Button类型添加Pou Tool
  482. /// 注:Button支持所有的Tool(双击打开Tool的对话框),但是只支持Button*类型的接口
  483. /// </summary>
  484. void DialogDataLink::AddPouToolsByButton(POU* pPou)
  485. {
  486. // 获取所有标准工具
  487. const QVector<TOOL*>& allTools = pPou->GetAllStandardTools();
  488. // 遍历所有的工具
  489. QVectorIterator<TOOL*> i(allTools);
  490. while (i.hasNext())
  491. {
  492. const TOOL* pTool = i.next();
  493. // 按照工具名称添加节点
  494. QTreeWidgetItem* pToolItem = AddToolTreeItem(pTool->strInstanceName);
  495. // 继续添加接口
  496. for (_INTERFACE* pInf : pTool->Interfaces)
  497. {
  498. // 接口可用,且是Button类型的(忽略输入还是输出,全部链接)
  499. if (pInf->bEnable
  500. && pInf->value.type == m_pControlObject->m_Type)
  501. {
  502. AddInterfaceTreeItem(pToolItem, pInf);
  503. }
  504. }
  505. }
  506. }
  507. /// <summary>
  508. /// 按Value数值类型添加Pou Tool
  509. /// ValueControl支持Pou中的非控件类型输入输出、全局变量、硬件局部变量
  510. /// </summary>
  511. void DialogDataLink::AddPouToolsByValue(POU* pPou)
  512. {
  513. // 获取所有标准工具
  514. const QVector<TOOL*>& allTools = pPou->GetAllStandardTools();
  515. // 遍历所有的工具
  516. QVectorIterator<TOOL*> i(allTools);
  517. while (i.hasNext())
  518. {
  519. const TOOL* pTool = i.next();
  520. // 按照工具名称添加节点
  521. QTreeWidgetItem* pToolItem = AddToolTreeItem(pTool->strInstanceName);
  522. // 继续添加接口
  523. int nInfCount = 0;
  524. for (_INTERFACE* pInf : pTool->Interfaces)
  525. {
  526. // 过滤掉隐藏接口,过滤掉控件类型,支持其他所有数据类型
  527. if ( pInf->bEnable
  528. && pInf->Type!=INF_TYPE::INF_TYPE_CONTROL )
  529. {
  530. // 符合过滤条件的接口添加到列表中
  531. AddInterfaceTreeItem(pToolItem, pInf);
  532. nInfCount++;
  533. }
  534. }
  535. // 如果没有有效的接口,则删除掉刚刚添加的Tool节点
  536. if (nInfCount <= 0)
  537. {
  538. ui.treeTool->removeItemWidget(pToolItem, 0);
  539. delete(pToolItem);
  540. }
  541. }
  542. }
  543. /// <summary>
  544. /// 按复杂控件类型添加Pou Tool
  545. /// 只支持数值类型接口
  546. /// </summary>
  547. /// <param name="pPou"></param>
  548. void DialogDataLink::AddPouToolsByComplexValue(POU* pPou)
  549. {
  550. // 获取所有标准工具
  551. const QVector<TOOL*>& allTools = pPou->GetAllStandardTools();
  552. // 遍历所有的工具
  553. QVectorIterator<TOOL*> i(allTools);
  554. while (i.hasNext())
  555. {
  556. const TOOL* pTool = i.next();
  557. // 按照工具名称添加节点
  558. QTreeWidgetItem* pToolItem = AddToolTreeItem(pTool->strInstanceName);
  559. // 继续添加接口
  560. int nInfCount = 0;
  561. for (_INTERFACE* pInf : pTool->Interfaces)
  562. {
  563. // 过滤掉隐藏接口
  564. // 只支持基础的数值类型
  565. // 只要输出接口
  566. if (pInf->bEnable
  567. && pInf->isBaseValueType()
  568. && pInf->Direction == INF_DIRECTION::INF_DIR_OUT
  569. )
  570. {
  571. // 符合过滤条件的接口添加到列表中
  572. AddInterfaceTreeItem(pToolItem, pInf);
  573. nInfCount++;
  574. }
  575. }
  576. // 如果没有有效的接口,则删除掉刚刚添加的Tool节点
  577. if (nInfCount <= 0)
  578. {
  579. ui.treeTool->removeItemWidget(pToolItem, 0);
  580. delete(pToolItem);
  581. }
  582. }
  583. }
  584. /// <summary>
  585. /// 按其他控件类型添加Pou Tool
  586. /// 只支持所有Pou里的相同输出控件类型
  587. /// </summary>
  588. void DialogDataLink::AddPouToolsByOther(POU* pPou)
  589. {
  590. // 获取所有标准工具
  591. const QVector<TOOL*>& allTools = pPou->GetAllStandardTools();
  592. // 遍历所有的工具
  593. QVectorIterator<TOOL*> i(allTools);
  594. while (i.hasNext())
  595. {
  596. const TOOL* pTool = i.next();
  597. // 按照工具名称添加节点
  598. QTreeWidgetItem* pToolItem = AddToolTreeItem(pTool->strInstanceName);
  599. // 继续添加接口
  600. int nInfCount = 0;
  601. for (_INTERFACE* pInf : pTool->Interfaces)
  602. {
  603. // 必须是可用接口,并且接口类型一致的输出接口
  604. if (pInf->bEnable
  605. && pInf->Direction ==INF_DIRECTION::INF_DIR_OUT
  606. && pInf->value.type == m_pControlObject->m_Type
  607. )
  608. {
  609. // 符合过滤条件的接口添加到列表中
  610. AddInterfaceTreeItem(pToolItem, pInf);
  611. nInfCount++;
  612. }
  613. }
  614. // 如果没有有效的接口,则删除掉刚刚添加的Tool节点
  615. if (nInfCount <= 0)
  616. {
  617. ui.treeTool->removeItemWidget(pToolItem, 0);
  618. delete(pToolItem);
  619. }
  620. }
  621. }
  622. /// <summary>
  623. /// 按照一些特殊的属性名称添加Pou Tool
  624. /// </summary>
  625. /// <param name="pPou"></param>
  626. void DialogDataLink::AddPouToolsByPropertyName(POU* pPou)
  627. {
  628. // 获取所有标准工具
  629. const QVector<TOOL*>& allTools = pPou->GetAllStandardTools();
  630. // 遍历所有的工具
  631. QVectorIterator<TOOL*> i(allTools);
  632. while (i.hasNext())
  633. {
  634. const TOOL* pTool = i.next();
  635. // 按照工具名称添加节点
  636. QTreeWidgetItem* pToolItem = AddToolTreeItem(pTool->strInstanceName);
  637. // 继续添加接口
  638. int nInfCount = 0;
  639. for (_INTERFACE* pInf : pTool->Interfaces)
  640. {
  641. // 必须是可用接口,并且接口类型一致的输出接口
  642. if (pInf->bEnable
  643. && pInf->Direction == INF_DIRECTION::INF_DIR_OUT
  644. && pInf->value.type == m_propertiesNameToType[m_strPropertyShortName]
  645. )
  646. {
  647. // 符合过滤条件的接口添加到列表中
  648. AddInterfaceTreeItem(pToolItem, pInf);
  649. nInfCount++;
  650. }
  651. }
  652. // 如果没有有效的接口,则删除掉刚刚添加的Tool节点
  653. if (nInfCount <= 0)
  654. {
  655. ui.treeTool->removeItemWidget(pToolItem, 0);
  656. delete(pToolItem);
  657. }
  658. }
  659. }
  660. /// <summary>
  661. /// 添加兼容的Pou变量到树形结构中
  662. /// </summary>
  663. /// <param name="strGroup"></param>
  664. /// <returns></returns>
  665. void DialogDataLink::AddPouVariablesToTree(const QString& strGroup)
  666. {
  667. // 获取指定的变量
  668. GVL* pGVL = g_pGvlManager->getGvl(strGroup);
  669. // 根据类型添加不同的表头
  670. QStringList title;
  671. if (pGVL->Type == TOOL_TYPE::TOOL_TYPE_GLOBAL_VARIABLE)
  672. {
  673. title << GROUP_GLOBAL_VARIABLE;
  674. }
  675. else
  676. {
  677. title << GROUP_LOCAL_VARIABLE;
  678. }
  679. // 添加父节点
  680. QTreeWidgetItem* pGroupItem = new QTreeWidgetItem(QStringList(title));
  681. pGroupItem->setIcon(0, QIcon(":/image/gvl_group_tree_item.png"));
  682. pGroupItem->setFlags(Qt::ItemIsEnabled);
  683. ui.treeTool->addTopLevelItem(pGroupItem);
  684. // 继续添加变量(Value以及所有的复杂控件都支持变量数值类型)
  685. const VARIABLES& vars = pGVL->Variables;
  686. for (const VARIABLE* var : vars)
  687. {
  688. if (var->bEnable)
  689. {
  690. // 2021-12-8 如果是复杂类型,需要做一下进一步的过滤
  691. if (m_pControlObject->isComplexControl())
  692. {
  693. // 只要基础数值类型和输出接口
  694. if (!(var->isBaseValueType()
  695. && var->isDirOutput()))
  696. {
  697. continue;
  698. }
  699. }
  700. AddInterfaceTreeItem(pGroupItem, var);
  701. }
  702. }
  703. }
  704. /// <summary>
  705. /// 添加Tool子节点
  706. /// </summary>
  707. /// <param name="toolName"></param>
  708. QTreeWidgetItem* DialogDataLink::AddToolTreeItem(const QString& toolName)
  709. {
  710. QTreeWidgetItem* newItem = new QTreeWidgetItem(QStringList(toolName));
  711. newItem->setIcon(0, QIcon(":/image/tool_tree_item.png"));
  712. // 除了Button类型可以选中父节点之外,别的类型都不允许选中父节点
  713. if (m_pControlObject->m_Type != VALUE_TYPE::Control_Button)
  714. {
  715. newItem->setFlags(Qt::ItemIsEnabled);
  716. }
  717. ui.treeTool->addTopLevelItem(newItem);
  718. return newItem;
  719. }
  720. /// <summary>
  721. /// 添加接口子节点
  722. /// </summary>
  723. void DialogDataLink::AddInterfaceTreeItem(QTreeWidgetItem* pToolItem, const _INTERFACE* pInf)
  724. {
  725. QTreeWidgetItem* newItem = new QTreeWidgetItem(pToolItem, QStringList(pInf->strNameWithType));
  726. if (pInf->Direction == INF_DIRECTION::INF_DIR_OUT)
  727. {
  728. newItem->setIcon(0, QIcon(":/image/Output.png"));
  729. }
  730. else
  731. {
  732. newItem->setIcon(0, QIcon(":/image/Input.png"));
  733. }
  734. pToolItem->addChild(newItem);
  735. }
  736. /// <summary>
  737. /// 获取DataLink
  738. /// </summary>
  739. /// <returns></returns>
  740. DataLink DialogDataLink::getValue() const
  741. {
  742. return m_DataLink;
  743. }
  744. /// <summary>
  745. /// 设置DataLink
  746. /// </summary>
  747. /// <param name="value"></param>
  748. void DialogDataLink::setValue(const DataLink& value)
  749. {
  750. m_DataLink = value;
  751. // ui.testEdit->setText(m_strInputValue);
  752. // TODO : 根据用户选择的值,将值同步到界面中
  753. }
  754. /// <summary>
  755. /// select按钮
  756. /// </summary>
  757. void DialogDataLink::onButtonSelectClicked()
  758. {
  759. // 获取用户选择的节点
  760. QList<QTreeWidgetItem*> selItems = ui.treeTool->selectedItems();
  761. // 如果尚未选择节点则报错
  762. if (selItems.size() <= 0)
  763. {
  764. Utility::VPCriticalMessageBox(" The item selected is invalid!");
  765. return;
  766. }
  767. // 清空之后重新选择
  768. m_DataLink.value.clear();
  769. // 获取选中的Item
  770. QTreeWidgetItem* selItem = selItems[0];
  771. // TODO: 此处需要根据DataLink的索引值关联到对应的控件DataLink序列中
  772. // 保存Button控件选择信息
  773. if (m_pControlObject->m_Type == VALUE_TYPE::Control_Button)
  774. {
  775. this->saveSelectionByButton(selItem);
  776. }
  777. // 保存其他控件类型选择信息
  778. else
  779. {
  780. this->saveSelectionByOther(selItem);
  781. }
  782. this->accept();
  783. }
  784. /// <summary>
  785. /// clear按钮(用于清空DataLink信息)
  786. /// </summary>
  787. void DialogDataLink::onButtonClearClicked()
  788. {
  789. // 确认清除数据连接信息
  790. QMessageBox::StandardButton ret = QUESTION_MESSAGE("Are you sure to clear the DataLink information?");
  791. if (ret == QMessageBox::Yes)
  792. {
  793. m_DataLink.value.clear();
  794. // 将界面设置未选中状态
  795. ui.comboValueGroup->setCurrentIndex(0);
  796. INFORMATION_MESSAGE("Clear DataLink information finished.");
  797. this->accept();
  798. }
  799. }
  800. /// <summary>
  801. /// 保存Button类型的相关信息
  802. /// </summary>
  803. bool DialogDataLink::saveSelectionByButton(QTreeWidgetItem* pItem)
  804. {
  805. // 不允许选中UI顶层节点
  806. if (pItem->text(0) == SYS_CMD_UI_SWITCH)
  807. {
  808. Utility::VPCriticalMessageBox(" The item selected is invalid!");
  809. return false;
  810. }
  811. m_DataLink.value.clear();
  812. // 分组信息
  813. m_DataLink.value << ui.comboValueGroup->currentText();
  814. // 保存信息
  815. // 如果选择的是顶层节点(几个系统命令或者是Tool本身)
  816. if(ui.treeTool->indexOfTopLevelItem(pItem)!=-1)
  817. {
  818. // 保存子类别和子项
  819. m_DataLink.value << pItem->text(0);
  820. m_DataLink.value << " ";
  821. }
  822. // UI切换选项和Tool导出的Button工具
  823. else
  824. {
  825. // 保存子类别和子项
  826. m_DataLink.value << pItem->parent()->text(0);
  827. // 去掉子项中的类型名称后缀
  828. QString strDetail = pItem->text(0);
  829. strDetail = strDetail.left(strDetail.indexOf("<") - 1);
  830. m_DataLink.value << strDetail;
  831. // m_pControlObject->m_Property.m_DataLink = m_DataLink;
  832. // 绑定指针用于后续同步
  833. if (!g_pUiManager->bindDataLinkSyncInformation(m_DataLink, m_pControlObject))
  834. {
  835. return false;
  836. }
  837. }
  838. return true;
  839. }
  840. /// <summary>
  841. /// 保存其他类型的选择信息
  842. /// </summary>
  843. bool DialogDataLink::saveSelectionByOther(QTreeWidgetItem* pItem)
  844. {
  845. // 不允许选择顶层节点
  846. if (ui.treeTool->indexOfTopLevelItem(pItem) != -1)
  847. {
  848. Utility::VPCriticalMessageBox(" The item selected is invalid!");
  849. return false;
  850. }
  851. // 保存信息
  852. // 分组
  853. m_DataLink.value << ui.comboValueGroup->currentText();
  854. // 子类别
  855. m_DataLink.value << pItem->parent()->text(0);
  856. // 子项
  857. // 去掉子项中的类型名称后缀
  858. QString strDetail = pItem->text(0);
  859. strDetail = strDetail.left(strDetail.indexOf("<") - 1);
  860. m_DataLink.value << strDetail;
  861. // 2022-2-10,在此之前需要先解绑旧的接口绑定信息
  862. // 根据属性名找到对应的DataLink
  863. const DataLink& lastDataLink = m_pControlObject->getDataLinkByProperty(m_strPropertyName);
  864. // 如果存在旧的绑定信息,先执行解绑
  865. if (lastDataLink.isValid())
  866. {
  867. g_pUiManager->unbindDataLinkSyncInformation(lastDataLink, m_pControlObject);
  868. }
  869. // 绑定指针用于后续同步
  870. if (!g_pUiManager->bindDataLinkSyncInformation(m_DataLink, m_pControlObject))
  871. {
  872. return false;
  873. }
  874. return true;
  875. }