934 lines
54 KiB
Python
934 lines
54 KiB
Python
|
|
import json
|
|||
|
|
import base64
|
|||
|
|
import os
|
|||
|
|
import re
|
|||
|
|
import uuid
|
|||
|
|
from PyQt6 import *
|
|||
|
|
from PyQt6.QtCore import *
|
|||
|
|
from PyQt6.QtGui import *
|
|||
|
|
from PyQt6.QtWidgets import *
|
|||
|
|
from insertInstructionDlg import InsertInstructionDlg
|
|||
|
|
from insertTaskDlg import InsertTaskDlg
|
|||
|
|
from ui.Ui_taskForm import Ui_taskForm
|
|||
|
|
from createTaskDlg import CreateTaskDlg
|
|||
|
|
from chooseDeviceDlg import ChooseDeviceDlg
|
|||
|
|
from interfaceSession.interfaceManager import interfaceManager
|
|||
|
|
from instructionModel.instructionManager import instructionManager
|
|||
|
|
from taskModel.taskManager import taskManager
|
|||
|
|
from deviceModel.deviceManager import deviceManager
|
|||
|
|
from devmodelModel.devModelManager import devModelManager
|
|||
|
|
from taskGroupModel.taskGroupManager import taskGroupManager
|
|||
|
|
from taskInstructionModel.taskInstructionManager import taskInstructionManager
|
|||
|
|
from taskModel.taskActuatorManager import taskActuatorManager
|
|||
|
|
from devGroupModel.devGroupManager import devGroupManager
|
|||
|
|
from show_editor import CodeDialog
|
|||
|
|
from logs import log
|
|||
|
|
from common import NoWheelComboBox
|
|||
|
|
from common import TaskProgressBar
|
|||
|
|
from common import DragDropInfo
|
|||
|
|
from common import AlignNoDelegate
|
|||
|
|
from common import AlignDevDelegate
|
|||
|
|
from common import AlignTaskNoDelegate
|
|||
|
|
# from common import EventFilter
|
|||
|
|
from common import common
|
|||
|
|
class QxStandardItem(QStandardItem):
|
|||
|
|
def __init__(self, text='', parent=None):
|
|||
|
|
self.obj = parent
|
|||
|
|
super().__init__(text)
|
|||
|
|
def updateProgress(self, taskId, value, maxValue):
|
|||
|
|
obj = self.data(Qt.ItemDataRole.UserRole)
|
|||
|
|
if obj is not None and isinstance(obj, dict):
|
|||
|
|
if str(taskId) == str(obj.get('task_instruction_id')):
|
|||
|
|
self.obj.taskModelBlockSignals = True
|
|||
|
|
self.setData({'value': value, 'maximum': maxValue, 'task_instruction_id': obj.get('task_instruction_id'), 'name':obj.get('name')}, Qt.ItemDataRole.UserRole)
|
|||
|
|
self.obj.taskModelBlockSignals = False
|
|||
|
|
class ProgressBarDelegate(QStyledItemDelegate):
|
|||
|
|
def paint(self, painter, option, index):
|
|||
|
|
if index.column() == 6: # 仅对第二列添加进度条
|
|||
|
|
data = index.data(Qt.ItemDataRole.UserRole) # 获取进度条数据
|
|||
|
|
if data is not None and isinstance(data, dict):
|
|||
|
|
value = data.get('value', -9999)
|
|||
|
|
maximum = data.get('maximum', -9999)
|
|||
|
|
progress_rect = option.rect # 进度条的矩形边界
|
|||
|
|
progress_width = int((value / maximum) * progress_rect.width()) # 计算进度条的宽度
|
|||
|
|
progress_rect.adjust(2, 2, -2, -2)
|
|||
|
|
# 绘制进度条背景
|
|||
|
|
painter.fillRect(progress_rect, QColor("#F8FAFF"))
|
|||
|
|
# 绘制实际数值文本
|
|||
|
|
text = f"{value}/{maximum}"
|
|||
|
|
text_rect = QRect(option.rect)
|
|||
|
|
# text_rect.adjust(0, 0, -1, 0) # 调整文本矩形边界
|
|||
|
|
# 修改字体和颜色
|
|||
|
|
# font = QFont("Arial", 10, QFont.Weight.Bold) # 创建字体对象
|
|||
|
|
# painter.setFont(font) # 设置字体
|
|||
|
|
pen = painter.pen()
|
|||
|
|
pen.setColor(Qt.GlobalColor.black) # 设置画笔颜色为红色
|
|||
|
|
painter.setPen(pen)
|
|||
|
|
# 绘制实际进度
|
|||
|
|
progress_rect.setWidth(progress_width)
|
|||
|
|
if value == -1 and maximum == -1:
|
|||
|
|
return
|
|||
|
|
if value >=0 and maximum >= 1 :
|
|||
|
|
painter.fillRect(progress_rect, QColor("#007EFF"))
|
|||
|
|
painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter, text)
|
|||
|
|
else:
|
|||
|
|
super().paint(painter, option, index)
|
|||
|
|
class TaskForm(QWidget):
|
|||
|
|
|
|||
|
|
def __init__(self, parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
self.ui = Ui_taskForm()
|
|||
|
|
self.ui.setupUi(self)
|
|||
|
|
self.defaultScriptBase64 = "aW1wb3J0IHRpbWUNCg0Kc3RhcnRUaW1lID0gdGltZS50aW1lKCkgDQpjdXJyZW50SW5kZXggPSAwDQpjdXJyZW50U3RhdGUgPSAwDQpkYXRlX2Zvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyINCg0KZGVmIHRvVGltZSh0YXJnZXRfdGltZV9zdHIpOg0KICAgIHRhcmdldF90aW1lID0gdGltZS5ta3RpbWUodGltZS5zdHJwdGltZSh0YXJnZXRfdGltZV9zdHIsIGRhdGVfZm9ybWF0KSkNCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKQ0KICAgICPmm7TmlrDml7bpl7Tov5vluqYNCiAgICB1cGRhdGVUaW1lKHN0YXJ0VGltZSwgY3VycmVudF90aW1lLCB0YXJnZXRfdGltZSkNCiAgICBpZiBjdXJyZW50X3RpbWUgPiB0YXJnZXRfdGltZToNCiAgICAgICAgcmV0dXJuIFRydWUNCiAgICByZXR1cm4gRmFsc2UNCg0KZGVmIHRvRGF5KGRheXMpOiAgDQogICAgdGFyZ2V0X3RpbWUgPSBzdGFydFRpbWUgKyBmbG9hdChkYXlzKSAqIDg2NDAwICAjIOWwhuWkqeaVsOi9rOaNouS4uuenkuW5tuWKoOWIsHN0YXJ0VGltZeS4iiAgDQogICAgY3VycmVudF90aW1lID0gdGltZS50aW1lKCkgIA0KICAgIHVwZGF0ZVRpbWUoc3RhcnRUaW1lLCBjdXJyZW50X3RpbWUsIHRhcmdldF90aW1lKSAgDQogICAgcmV0dXJuIGN1cnJlbnRfdGltZSA+IHRhcmdldF90aW1lICANCg0KZGVmIHRvSG91cihob3Vycyk6ICANCiAgICB0YXJnZXRfdGltZSA9IHN0YXJ0VGltZSArIGZsb2F0KGhvdXJzKSAqIDM2MDAgICMg5bCG5bCP5pe26L2s5o2i5Li656eS5bm25Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICAgDQpkZWYgdG9NaW51dGUobWludXRlcyk6ICANCiAgICB0YXJnZXRfdGltZSA9IHN0YXJ0VGltZSArIGZsb2F0KG1pbnV0ZXMpICogNjAgICMg5bCG5YiG6ZKf6L2s5o2i5Li656eS5bm25Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICANCmRlZiB0b1NlY29uZChzZWNvbmRzKTogIA0KICAgIHRhcmdldF90aW1lID0gc3RhcnRUaW1lICsgZmxvYXQoc2Vjb25kcykgICMg5bCG56eS55u05o6l5Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICAgIA0KZGVmIGNhbGxCYWNrKGNvbXBsZXRlZF9zdGF0ZSk6DQogICAgZ2xvYmFsIGN1cnJlbnRJbmRleCwgY3VycmVudFN0YXRlDQogICAgY3VycmVudFN0YXRlID0gY29tcGxldGVkX3N0YXRlICMwOiDov5vlhaXku7vliqE7ICAx77ya5omn6KGM5Lu75YqhOyAgMu+8muaJp+ihjOaMh+S7pDsgIDPvvJrnrYnlvoXmjIfku6TplIHop6PpmaQ7ICA077yaIOaMh+S7pOW+queOrw0KICAgICNsb2coZiJjb21wbGV0ZWRfc3RhdGUgPXtjb21wbGV0ZWRfc3RhdGV9ICwgY3VycmVudEluZGV4ID0ge2N1cnJlbnRJbmRleH0sIHRhc2tQcm9jZXNzRmxhZyA9IHt0YXNrUHJvY2Vzc0ZsYWd9IikNCiAgICBpZiBsb29wID09IDA6DQogICAgICAgIGlmIGN1cnJlbnRJbmRleCA9PSAwOiAgICAgICAgICAgI+mmluasoei/m+WFpemYn+WIlw0KICAgICAgICAgICAgbG9nKGYiSW5pdGlhbGl6aW5nIGhlcmUuIikNCiAgICAgICAgICAgIGN1cnJlbnRJbmRleCArPSAxDQogICAgICAgICAgICB0aW1lLnNsZWVwKDEpDQogICAgICAgICAgICANCiAgICAgICAgbG9nKGYiY29tcGxldGVkX3N0YXRlID17Y29tcGxldGVkX3N0YXRlfSIpDQogICAgICAgICMg5Lu75Yqh5b6q546v5qyh5pWwPTAg5pe25Y+v55SoDQogICAgICAgICNpZiB0b1RpbWUoIjIwMjQtMDEtMDUgMjA6MDA6MDAiKToNCiAgICAgICAgIyAgICBmaW5pc2goKQ0KICAgICAgICAjaWYgdG9EYXkoMSk6DQogICAgICAgICMgICAgZmluaXNoKCkgICAgDQogICAgICAgICNpZiB0b0hvdXIoMSk6DQogICAgICAgICMgICAgZmluaXNoKCkNCiAgICAgICAgaWYgdG9NaW51dGUoMSk6DQogICAgICAgICAgICBmaW5pc2goKQ0KICAgICAgICAjaWYgdG9TZWNvbmQoMzApOg0KICAgICAgICAjICAgIGZpbmlzaCgpDQogICAgZWxzZTogDQogICAgICAgIG1hdGNoIGNvbXBsZXRlZF9zdGF0ZToNCiAgICAgICAgICAgIGNhc2UgMDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICPov5vlhaXpmJ/liJcNCiAgICAgICAgICAgICAgICBpZiBjdXJyZW50SW5kZXggPT0gMDogICAgICAgICAgICPpppbmrKHov5vlhaXpmJ/liJcNCiAgICAgICAgICAgICAgICAgICAgbG9nKGYiSW5pdGlhbGl6aW5nIGhlcmUuIikNCiAgICAgICAgICAgICAgICAgICAgdGltZS5zbGVlcCg1KQ0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgY2FzZSAxOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI+aJp+ihjOmYn+WIlw0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgY2FzZSAyOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI+aJp+ihjOaMh+S7pA0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KDQpkZWYgbmV4dCgpOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAj6Zif5YiX5Y2V5qyh5omn6KGM5a6M5q+V5ZCO6LCD55SoDQogICAgZ2xvYmFsIGN1cnJlbnRJbmRleCwgY3VycmVudFN0YXRlDQogICAgY3VycmVudEluZGV4ID0gY3V
|
|||
|
|
self.taskModelBlockSignals = False
|
|||
|
|
self.taskDetailModelBlockSignals = False
|
|||
|
|
self.taskGroupModelSignalsBlock = False
|
|||
|
|
self.confInterfaces = interfaceManager.getInfo()
|
|||
|
|
self.supportedTypes = instructionManager.getSupportedType()
|
|||
|
|
self.codeDialog = CodeDialog("脚本编辑")
|
|||
|
|
self.chooseDeviceDlg = ChooseDeviceDlg()
|
|||
|
|
self.createTaskDlg = CreateTaskDlg()
|
|||
|
|
self.insertInstructionDlg = InsertInstructionDlg()
|
|||
|
|
self.insertTaskDlg = InsertTaskDlg()
|
|||
|
|
self.current_groupId = None
|
|||
|
|
self.topWidget = None
|
|||
|
|
self.taskModel = QStandardItemModel()
|
|||
|
|
self.taskGroupModel = QStandardItemModel()
|
|||
|
|
self.taskDetailModel = QStandardItemModel()
|
|||
|
|
self.taskDetailDescriptionModel = QStandardItemModel()
|
|||
|
|
self.rootItem = self.taskDetailDescriptionModel.invisibleRootItem()
|
|||
|
|
self.ui.treeViewDescription.setModel(self.taskDetailDescriptionModel)
|
|||
|
|
self.ui.treeViewDescription.setColumnWidth(0, 400)
|
|||
|
|
self.ui.treeViewDescription.setHeaderHidden(True)
|
|||
|
|
self.insertInstructionDlg.accepted.connect(self.refreshTaskDetail)
|
|||
|
|
self.insertTaskDlg.accepted.connect(self.refreshTaskDetail)
|
|||
|
|
self.createTaskDlg.createFinished.connect(self.createTaskFinished)
|
|||
|
|
self.createTaskDlg.editFinished.connect(self.editTaskFinished)
|
|||
|
|
self.chooseDeviceDlg.chooseFinished.connect(self.chooseDeviceFinished)
|
|||
|
|
self.ui.pbInsertInstruction.clicked.connect(self.insertInstruction)
|
|||
|
|
self.ui.pbInsertTask.clicked.connect(self.insertTask)
|
|||
|
|
self.taskModel.itemChanged.connect(self.updateTask)
|
|||
|
|
self.taskGroupModel.itemChanged.connect(self.updateTaskGroup)
|
|||
|
|
self.taskDetailModel.itemChanged.connect(self.updateTaskInstruction)
|
|||
|
|
self.ui.tableViewTask.setModel(self.taskModel)
|
|||
|
|
self.ui.tableViewTaskGroup.setModel(self.taskGroupModel)
|
|||
|
|
self.ui.tableViewTaskGroup.dropEvent = self.dropEvent
|
|||
|
|
self.ui.pbEditTaskScript.clicked.connect(self.editTaskScript)
|
|||
|
|
self.ui.pbCopyTask.clicked.connect(self.copyTask)
|
|||
|
|
self.ui.pbExportTask.clicked.connect(self.exportTask)
|
|||
|
|
self.ui.tableViewTaskDetail.setModel(self.taskDetailModel)
|
|||
|
|
self.ui.tableViewTaskDetail.doubleClicked.connect(self.editTaskDetail)
|
|||
|
|
self.ui.tableViewTaskDetail.selectionModel().selectionChanged.connect(self.handleTaskDetailSelection)
|
|||
|
|
self.ui.pbCreateGroup.clicked.connect(self.createGroup)
|
|||
|
|
self.ui.pbDeleteGroup.clicked.connect(self.deleteGroup)
|
|||
|
|
self.ui.pbCreateTask.clicked.connect(self.createTask)
|
|||
|
|
self.ui.pbEditTask.clicked.connect(self.editTask)
|
|||
|
|
self.ui.pbDeleteTask.clicked.connect(self.deleteTask)
|
|||
|
|
self.ui.pbUp.clicked.connect(self.handleUpClick)
|
|||
|
|
self.ui.pbDown.clicked.connect(self.handleDownClick)
|
|||
|
|
self.ui.pbDeleteTaskDetail.clicked.connect(self.deleteTaskDetail)
|
|||
|
|
self.ui.pbSort.clicked.connect(self.showSortBtn)
|
|||
|
|
self.ui.pbStartTask.clicked.connect(self.startTask)
|
|||
|
|
self.ui.pbStopTask.clicked.connect(self.stopTask)
|
|||
|
|
self.ui.pbSaveSort.clicked.connect(self.saveSort)
|
|||
|
|
self.ui.pbEditScript.clicked.connect(self.editScript)
|
|||
|
|
self.subTasks = {}
|
|||
|
|
self.hideSortBtn()
|
|||
|
|
self.ui.tableViewTaskGroup.selectionModel().selectionChanged.connect(self.handleGroupSelection)
|
|||
|
|
self.ui.tableViewTask.selectionModel().selectionChanged.connect(self.handleTaskSelection)
|
|||
|
|
self.setSplitterStretchFactor()
|
|||
|
|
self.batchSetItemDelegate()
|
|||
|
|
|
|||
|
|
def batchSetItemDelegate(self):
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
|||
|
|
self.ui.tableViewTaskGroup.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
|||
|
|
self.ui.tableViewTask.setItemDelegate(AlignTaskNoDelegate(self.ui.tableViewTask))
|
|||
|
|
self.ui.tableViewTaskGroup.setItemDelegate(AlignNoDelegate(self.ui.tableViewTaskGroup))
|
|||
|
|
self.ui.tableViewTaskDetail.setItemDelegate(AlignDevDelegate(self.ui.tableViewTaskDetail,2))
|
|||
|
|
|
|||
|
|
def dropEvent(self, event: QDropEvent):
|
|||
|
|
if event.source() != self:
|
|||
|
|
mime_data = event.mimeData()
|
|||
|
|
source_index = mime_data.data('application/x-qabstractitemmodeldatalist')
|
|||
|
|
target_pos = event.position()
|
|||
|
|
target_index = self.ui.tableViewTaskGroup.indexAt(QPoint(int(target_pos.x()), int(target_pos.y())))
|
|||
|
|
drag_drop_info = DragDropInfo(source_index, target_index)
|
|||
|
|
self.handleDrop(drag_drop_info)
|
|||
|
|
event.accept()
|
|||
|
|
else:
|
|||
|
|
event.ignore()
|
|||
|
|
|
|||
|
|
# 双击编辑任务功能
|
|||
|
|
def editTaskDetail(self, index):
|
|||
|
|
rows = self.ui.tableViewTaskDetail.selectionModel().selectedRows()
|
|||
|
|
if len(rows) == 1:
|
|||
|
|
row = rows[0].row()
|
|||
|
|
if index.column() == 3:
|
|||
|
|
row_id_index = self.taskDetailModel.index(row, 0, QModelIndex())
|
|||
|
|
row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex())
|
|||
|
|
id = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
target_id = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
self.chooseDeviceDlg.showChooseDeviceDlg(id, target_id)
|
|||
|
|
|
|||
|
|
def handleDrop(self, drag_drop_info):
|
|||
|
|
target_row = drag_drop_info.target_index.row()
|
|||
|
|
if target_row > -1:
|
|||
|
|
row_id_index = self.taskGroupModel.index(target_row, 0, QModelIndex())
|
|||
|
|
groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
rows = self.ui.tableViewTask.selectionModel().selectedRows()
|
|||
|
|
for row in rows:
|
|||
|
|
row_id_index = self.taskModel.index(row.row(), 0, QModelIndex())
|
|||
|
|
taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskParam = {
|
|||
|
|
"group_id": groupId
|
|||
|
|
}
|
|||
|
|
result = taskManager.update(taskId, taskParam)
|
|||
|
|
self.refreshSelect()
|
|||
|
|
|
|||
|
|
def editScript(self):
|
|||
|
|
indexs = self.ui.tableViewTask.selectionModel().selectedRows()
|
|||
|
|
if len(indexs) == 1:
|
|||
|
|
if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex())
|
|||
|
|
row_devicename_index = self.taskDetailModel.index(row, 3, QModelIndex())
|
|||
|
|
devicename = self.taskDetailModel.data(row_devicename_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
target_id = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if devicename == "任务":
|
|||
|
|
task = taskManager.getInfo(target_id)
|
|||
|
|
if task:
|
|||
|
|
scriptStr = task["script"] and str(base64.b64decode(task["script"] ), 'utf-8') or str(base64.b64decode(self.defaultScriptBase64).decode('utf-8'))
|
|||
|
|
scriptStr = self.codeDialog.showEditDlg(scriptStr,"task")
|
|||
|
|
if scriptStr == "":
|
|||
|
|
return
|
|||
|
|
script = base64.b64encode(scriptStr.encode("utf-8"))
|
|||
|
|
param = {
|
|||
|
|
"script": script
|
|||
|
|
}
|
|||
|
|
result = taskManager.update(target_id, param)
|
|||
|
|
else:
|
|||
|
|
instruction = instructionManager.getInfo(target_id)
|
|||
|
|
if instruction != None:
|
|||
|
|
dataAttr = instruction.get('attr')
|
|||
|
|
if dataAttr != None:
|
|||
|
|
if dataAttr.get('script') != None:
|
|||
|
|
base64_encoded_str = dataAttr.get('script')
|
|||
|
|
result = self.codeDialog.showEditDlg(str(base64.b64decode(base64_encoded_str).decode('utf-8')))
|
|||
|
|
if result == "":
|
|||
|
|
return
|
|||
|
|
script = base64.b64encode(result.encode("utf-8")).decode('utf-8')
|
|||
|
|
dataAttr['script'] = script
|
|||
|
|
instructionManager.update(target_id, {"attr": dataAttr})
|
|||
|
|
script = base64.b64encode(result.encode("utf-8")).decode('utf-8')
|
|||
|
|
dataAttr['script'] = script
|
|||
|
|
instructionManager.update(target_id, {"attr": dataAttr})
|
|||
|
|
|
|||
|
|
def editTaskScript(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
task_id = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
task = taskManager.getInfo(task_id)
|
|||
|
|
if task:
|
|||
|
|
scriptStr = task["script"] and str(base64.b64decode(task["script"] ), 'utf-8') or str(base64.b64decode(self.defaultScriptBase64).decode('utf-8'))
|
|||
|
|
scriptStr = self.codeDialog.showEditDlg(scriptStr,"task")
|
|||
|
|
if scriptStr == "":
|
|||
|
|
return
|
|||
|
|
script = base64.b64encode(scriptStr.encode("utf-8"))
|
|||
|
|
param = {
|
|||
|
|
"script": script
|
|||
|
|
}
|
|||
|
|
result = taskManager.update(task_id, param)
|
|||
|
|
def startTask(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskActuatorManager.start(taskid)
|
|||
|
|
|
|||
|
|
def stopTask(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskActuatorManager.stop(taskid)
|
|||
|
|
|
|||
|
|
def copyTask(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskManager.createCopy(taskid)
|
|||
|
|
self.refreshSelect()
|
|||
|
|
|
|||
|
|
# 覆盖方式导入设备模型
|
|||
|
|
def overWriteTask(self):
|
|||
|
|
file_dialog = QFileDialog(self)
|
|||
|
|
file_dialog.setWindowTitle("选择JSON")
|
|||
|
|
file_dialog.setNameFilter("Supported file formats (*.json)")
|
|||
|
|
file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
|
|||
|
|
if file_dialog.exec():
|
|||
|
|
file_path = file_dialog.selectedFiles()[0]
|
|||
|
|
with open(file_path, "r", encoding="utf-8") as f: # 指定以utf-8编码打开文件
|
|||
|
|
taskInfo = json.load(f)
|
|||
|
|
tasks = taskInfo.get("tasks",[])
|
|||
|
|
instructions = taskInfo.get("task_instructions",[])
|
|||
|
|
for task in tasks:
|
|||
|
|
groupId = task['group_id']
|
|||
|
|
group_name = task['group_name']
|
|||
|
|
if groupId != None:
|
|||
|
|
if taskGroupManager.getInfo( groupId ) == None:
|
|||
|
|
groupId = taskGroupManager.create({"id": groupId, "name": group_name})
|
|||
|
|
task['group_id'] = groupId
|
|||
|
|
task_id = task['id']
|
|||
|
|
if taskManager.getInfo(task_id) != None:
|
|||
|
|
taskManager.update(task_id, task)
|
|||
|
|
else:
|
|||
|
|
task_id = taskManager.create_from_json(task)
|
|||
|
|
|
|||
|
|
for instruction in instructions:
|
|||
|
|
instructionId = instruction['id']
|
|||
|
|
if instruction["task_id"] == task_id:
|
|||
|
|
if taskInstructionManager.getInstructionInfo(instructionId) != None:
|
|||
|
|
taskInstructionManager.update(instructionId, instruction)
|
|||
|
|
else:
|
|||
|
|
taskInstructionManager.create_from_json(instruction)
|
|||
|
|
self.refreshSelect()
|
|||
|
|
|
|||
|
|
def exportSingleTask(self, task_id):
|
|||
|
|
tInfo = taskManager.getInfo(task_id)
|
|||
|
|
#判断taskInfo 中的Id 长度是否小于10,如果是则改为uuid
|
|||
|
|
new_task_id = str(uuid.uuid4())
|
|||
|
|
if len(str(task_id)) < 10:
|
|||
|
|
tInfo["id"] = new_task_id
|
|||
|
|
common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task", tInfo)
|
|||
|
|
groupInfo = taskGroupManager.getInfo(tInfo["group_id"])
|
|||
|
|
common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task_group", groupInfo)
|
|||
|
|
task_instructionInfos = taskInstructionManager.getTaskInstructions(task_id)
|
|||
|
|
for task_instructionInfo in task_instructionInfos:
|
|||
|
|
if len(str(task_instructionInfo["id"])) < 10:
|
|||
|
|
task_instructionInfo["id"] = str(uuid.uuid4())
|
|||
|
|
if len(task_id) < 10:
|
|||
|
|
task_instructionInfo["task_id"] = new_task_id
|
|||
|
|
target_type = task_instructionInfo["target_type"]
|
|||
|
|
if target_type == "instruction":
|
|||
|
|
deviceInfo = deviceManager.getOriginalInfo(task_instructionInfo["device_id"])
|
|||
|
|
groupInfo = devGroupManager.getInfo(deviceInfo["group_id"])
|
|||
|
|
if deviceInfo!= None:
|
|||
|
|
common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"device", deviceInfo)
|
|||
|
|
if groupInfo!= None:
|
|||
|
|
common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"device_group", groupInfo)
|
|||
|
|
elif target_type == "task":
|
|||
|
|
self.exportSingleTask(task_instructionInfo["target_id"])
|
|||
|
|
common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task_instruction", task_instructionInfo)
|
|||
|
|
|
|||
|
|
def exportTask(self):
|
|||
|
|
try:
|
|||
|
|
filename = "data.zip"
|
|||
|
|
packeagePath = filename
|
|||
|
|
fname = QFileDialog.getSaveFileName(self, '保存文件', packeagePath, 'JSON files (*.zip)')
|
|||
|
|
if fname[0]:
|
|||
|
|
packeagePath = fname[0]
|
|||
|
|
exportPath = os.path.join(os.path.dirname(__file__),"export")
|
|||
|
|
#清空exportPath目录
|
|||
|
|
common.clearDir(exportPath)
|
|||
|
|
#创建exportPath目录
|
|||
|
|
common.createDir(exportPath)
|
|||
|
|
indexs = self.ui.tableViewTask.selectionModel().selectedRows()
|
|||
|
|
for index in indexs:
|
|||
|
|
row = index.row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
task_id = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
self.exportSingleTask(task_id)
|
|||
|
|
common.writeZip(packeagePath, exportPath)
|
|||
|
|
except Exception as e:
|
|||
|
|
if self.topWidget == None:
|
|||
|
|
self.topWidget = self.findTopLevelParent(self)
|
|||
|
|
if self.topWidget != None:
|
|||
|
|
self.topWidget.alertDialog(e,"导出文件异常")
|
|||
|
|
|
|||
|
|
def chooseDeviceFinished(self):
|
|||
|
|
self.refreshTaskDetail()
|
|||
|
|
|
|||
|
|
def saveSort(self):
|
|||
|
|
for row in range(self.taskDetailModel.rowCount()):
|
|||
|
|
row_id_index = self.taskDetailModel.index(row, 0, QModelIndex())
|
|||
|
|
row_level_index = self.taskDetailModel.index(row, 10, QModelIndex())
|
|||
|
|
taskInstanceId = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
level = self.taskDetailModel.data(row_level_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if not str(row) == level:
|
|||
|
|
param = {
|
|||
|
|
"level": row
|
|||
|
|
}
|
|||
|
|
if not taskInstructionManager.update(taskInstanceId, param):
|
|||
|
|
print("update error")
|
|||
|
|
self.refreshTaskDetail()
|
|||
|
|
self.hideSortBtn()
|
|||
|
|
|
|||
|
|
def createGroup(self):
|
|||
|
|
index = self.taskGroupModel.rowCount()
|
|||
|
|
self.taskGroupModel.appendRow([ QStandardItem(),QStandardItem(str(index+1)), QStandardItem()])
|
|||
|
|
self.ui.tableViewTaskGroup.setCurrentIndex(self.taskGroupModel.index(index, 0) )
|
|||
|
|
self.ui.tableViewTaskGroup.edit(self.taskGroupModel.index(index, 2))
|
|||
|
|
|
|||
|
|
def deleteGroup(self):
|
|||
|
|
if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_id_index = self.taskGroupModel.index(row, 0, QModelIndex())
|
|||
|
|
groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if groupId == common.defaultGroupId:
|
|||
|
|
return
|
|||
|
|
row_groupName_index = self.taskGroupModel.index(row, 2, QModelIndex())
|
|||
|
|
groupName = self.taskGroupModel.data(row_groupName_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if self.topWidget == None:
|
|||
|
|
self.topWidget = self.findTopLevelParent(self)
|
|||
|
|
if self.topWidget != None:
|
|||
|
|
if self.taskModel.rowCount() > 0:
|
|||
|
|
self.topWidget.alertDialog("分组下存在任务,不能删除分组", "警告")
|
|||
|
|
return
|
|||
|
|
if self.topWidget.removeDialog(groupName,"删除分组"):
|
|||
|
|
result = taskGroupManager.delete(groupId)
|
|||
|
|
if result == True:
|
|||
|
|
self.clearChildrenModel()
|
|||
|
|
self.taskGroupModel.removeRow(row)
|
|||
|
|
|
|||
|
|
def updateTaskGroup(self):
|
|||
|
|
if self.taskGroupModelSignalsBlock == False:
|
|||
|
|
if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_id_index = self.taskGroupModel.index(row, 0, QModelIndex())
|
|||
|
|
groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
row_nane_index = self.taskGroupModel.index(row, 2, QModelIndex())
|
|||
|
|
groupName = self.taskGroupModel.data(row_nane_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if groupId == None:
|
|||
|
|
groupId = taskGroupManager.create({"name":groupName})
|
|||
|
|
self.taskGroupModel.setData(row_id_index, groupId)
|
|||
|
|
else:
|
|||
|
|
taskGroupManager.update(groupId, {"name":groupName})
|
|||
|
|
|
|||
|
|
def showSortBtn(self):
|
|||
|
|
self.ui.pbUp.setVisible(True)
|
|||
|
|
self.ui.pbDown.setVisible(True)
|
|||
|
|
self.ui.pbSaveSort.setVisible(True)
|
|||
|
|
self.ui.pbDeleteTaskDetail.setVisible(False)
|
|||
|
|
self.ui.pbDeleteTask.setEnabled(False)
|
|||
|
|
self.ui.pbSort.setVisible(False)
|
|||
|
|
self.ui.pbInsertInstruction.setVisible(False)
|
|||
|
|
self.ui.pbInsertTask.setVisible(False)
|
|||
|
|
self.ui.pbEditScript.setVisible(False)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(9, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(8, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(7, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(6, True)
|
|||
|
|
self.setAllColumnWidth()
|
|||
|
|
|
|||
|
|
def hideSortBtn(self):
|
|||
|
|
self.ui.pbUp.setVisible(False)
|
|||
|
|
self.ui.pbDown.setVisible(False)
|
|||
|
|
self.ui.pbSaveSort.setVisible(False)
|
|||
|
|
self.ui.pbSort.setVisible(True)
|
|||
|
|
self.ui.pbDeleteTaskDetail.setVisible(True)
|
|||
|
|
self.ui.pbDeleteTask.setEnabled(True)
|
|||
|
|
self.ui.pbInsertInstruction.setVisible(True)
|
|||
|
|
self.ui.pbInsertTask.setVisible(True)
|
|||
|
|
self.ui.pbEditScript.setVisible(True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(9, False)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(8, False)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(7, False)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(6, False)
|
|||
|
|
self.setAllColumnWidth()
|
|||
|
|
|
|||
|
|
def insertTask(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
taskId=self.taskModel.item(row, 0).text()
|
|||
|
|
position = self.taskDetailModel.rowCount()
|
|||
|
|
self.insertTaskDlg.showDlg(taskId, position)
|
|||
|
|
|
|||
|
|
def insertInstruction(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
taskId=self.taskModel.item(row, 0).text()
|
|||
|
|
position = self.taskDetailModel.rowCount()
|
|||
|
|
self.insertInstructionDlg.showDlg(taskId, position)
|
|||
|
|
|
|||
|
|
def createTaskFinished(self):
|
|||
|
|
self.loadTask()
|
|||
|
|
if self.taskModel.rowCount() > 0:
|
|||
|
|
self.ui.tableViewTask.selectRow(self.taskModel.rowCount()-1)
|
|||
|
|
|
|||
|
|
def editTaskFinished(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
self.loadTask()
|
|||
|
|
if self.taskModel.rowCount() > 0:
|
|||
|
|
self.ui.tableViewTask.selectRow(row)
|
|||
|
|
|
|||
|
|
def createTask(self):
|
|||
|
|
if self.current_groupId != None:
|
|||
|
|
self.createTaskDlg.showCreateDlg(self.current_groupId)
|
|||
|
|
|
|||
|
|
def editTask(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_taskId_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
task_id = self.taskModel.data(row_taskId_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
task = taskManager.getInfo(task_id)
|
|||
|
|
if task:
|
|||
|
|
self.createTaskDlg.showEditDlg(task)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def findTopLevelParent(self, widget):
|
|||
|
|
parent = widget.parent()
|
|||
|
|
while parent and not isinstance(parent, QMainWindow): # 顶层窗口是 QMainWindow
|
|||
|
|
widget = parent
|
|||
|
|
parent = widget.parent()
|
|||
|
|
return parent
|
|||
|
|
|
|||
|
|
def deleteTask(self):
|
|||
|
|
indexs = self.ui.tableViewTask.selectionModel().selectedRows()
|
|||
|
|
if len(indexs) == 1:
|
|||
|
|
row = indexs[0].row()
|
|||
|
|
row_id_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
row_name_index = self.taskModel.index(row, 2, QModelIndex())
|
|||
|
|
taskName = self.taskModel.data(row_name_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if self.topWidget == None:
|
|||
|
|
self.topWidget = self.findTopLevelParent(self)
|
|||
|
|
if self.topWidget != None:
|
|||
|
|
if self.topWidget.removeDialog(taskName,"删除任务"):
|
|||
|
|
row_taskModel_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
result = taskManager.delete(self.taskModel.data(row_taskModel_index, Qt.ItemDataRole.DisplayRole))
|
|||
|
|
if result == True:
|
|||
|
|
self.refreshSelect()
|
|||
|
|
elif len(indexs) > 1:
|
|||
|
|
if self.topWidget == None:
|
|||
|
|
self.topWidget = self.findTopLevelParent(self)
|
|||
|
|
if self.topWidget != None: #必须这样写,不能写else
|
|||
|
|
if self.topWidget.removeDialog(f"{len(indexs)}个任务"):
|
|||
|
|
for index in indexs:
|
|||
|
|
row = index.row()
|
|||
|
|
row_id_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskManager.delete(taskId)
|
|||
|
|
self.refreshSelect()
|
|||
|
|
|
|||
|
|
def clearChildrenModel(self):
|
|||
|
|
self.taskDetailModel.clear()
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
|
|||
|
|
def clearTaskChildrenModel(self):
|
|||
|
|
self.taskModel.clear()
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
|
|||
|
|
def handleUpClick(self):
|
|||
|
|
selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows()
|
|||
|
|
if len(selectRows) == 1:
|
|||
|
|
row = selectRows[0].row()
|
|||
|
|
if row > 0:
|
|||
|
|
item = self.taskDetailModel.takeRow(row)
|
|||
|
|
self.taskDetailModel.insertRow(row - 1, item)
|
|||
|
|
self.ui.tableViewTaskDetail.selectRow(row - 1)
|
|||
|
|
|
|||
|
|
def handleDownClick(self):
|
|||
|
|
selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows()
|
|||
|
|
if len(selectRows) == 1:
|
|||
|
|
row = selectRows[0].row()
|
|||
|
|
if row < self.taskDetailModel.rowCount() - 1:
|
|||
|
|
item = self.taskDetailModel.takeRow(row)
|
|||
|
|
self.taskDetailModel.insertRow(row + 1, item)
|
|||
|
|
self.ui.tableViewTaskDetail.selectRow(row + 1)
|
|||
|
|
|
|||
|
|
def refreshSelect(self):
|
|||
|
|
selectedRows = self.ui.tableViewTaskGroup.selectionModel().selectedRows()
|
|||
|
|
self.loadTaskGroup()
|
|||
|
|
if len(selectedRows) < 1:
|
|||
|
|
self.ui.tableViewTaskGroup.selectRow(0)
|
|||
|
|
if len(selectedRows) == 1:
|
|||
|
|
row = selectedRows[0].row()
|
|||
|
|
self.ui.tableViewTaskGroup.selectRow(row)
|
|||
|
|
|
|||
|
|
def refreshTaskDetail(self):
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
self.loadTaskDetail(taskid)
|
|||
|
|
|
|||
|
|
# 任务分组选中
|
|||
|
|
def handleGroupSelection(self, index):
|
|||
|
|
if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_id_index = self.taskGroupModel.index(row, 0, QModelIndex())
|
|||
|
|
group_id = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
self.current_groupId = group_id
|
|||
|
|
self.loadTask()
|
|||
|
|
self.clearChildrenModel()
|
|||
|
|
|
|||
|
|
#任务列表选中
|
|||
|
|
def handleTaskSelection(self, index):
|
|||
|
|
self.refreshTaskDetail()
|
|||
|
|
|
|||
|
|
def handleTaskDetailSelection(self, index):
|
|||
|
|
if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex())
|
|||
|
|
targetId = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
row_target_type_name_index = self.taskDetailModel.index(row, 3, QModelIndex())
|
|||
|
|
targetTypeName = self.taskDetailModel.data(row_target_type_name_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if targetTypeName == "任务":
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
self.appendTaskItem(targetId)
|
|||
|
|
self.ui.stackedWidgetDescription.setCurrentIndex(1)
|
|||
|
|
else:
|
|||
|
|
info = instructionManager.getInfo(targetId)
|
|||
|
|
attr = info.get('attr')
|
|||
|
|
if attr == None:
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
else:
|
|||
|
|
description = attr.get('description')
|
|||
|
|
if description == None:
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
else:
|
|||
|
|
self.ui.textEditDescription.setText(description)
|
|||
|
|
self.ui.stackedWidgetDescription.setCurrentIndex(0)
|
|||
|
|
|
|||
|
|
def appendTaskItem(self, taskId):
|
|||
|
|
try:
|
|||
|
|
task = taskManager.getInfo(str(taskId))
|
|||
|
|
if task:
|
|||
|
|
name = task["name"]
|
|||
|
|
item = QStandardItem(str(name))
|
|||
|
|
self.appendChildTask(item, str(taskId))
|
|||
|
|
self.rootItem.appendRow([item])
|
|||
|
|
self.ui.treeViewDescription.expandAll()
|
|||
|
|
except Exception as e:
|
|||
|
|
print(e)
|
|||
|
|
def appendChildTask(self, parent, taskId):
|
|||
|
|
try:
|
|||
|
|
taskInstructions = taskInstructionManager.getInfo(taskId)
|
|||
|
|
if taskInstructions:
|
|||
|
|
for taskInstruction in taskInstructions:
|
|||
|
|
target_type = taskInstruction["target_type"]
|
|||
|
|
task_instruction_id = str(taskInstruction["id"])
|
|||
|
|
level = taskInstruction["level"]
|
|||
|
|
if target_type == "task":
|
|||
|
|
task = taskManager.getInfo(str(taskInstruction["target_id"]))
|
|||
|
|
if task:
|
|||
|
|
name = task["name"]
|
|||
|
|
childItem = QStandardItem(str(name))
|
|||
|
|
parent.appendRow([childItem])
|
|||
|
|
except Exception as e:
|
|||
|
|
print(e)
|
|||
|
|
|
|||
|
|
def deleteTaskDetail(self):
|
|||
|
|
if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_name_index = self.taskDetailModel.index(row, 4, QModelIndex())
|
|||
|
|
targetName = self.taskDetailModel.data(row_name_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if self.topWidget == None:
|
|||
|
|
self.topWidget = self.findTopLevelParent(self)
|
|||
|
|
if self.topWidget != None:
|
|||
|
|
if self.topWidget.removeDialog(targetName,"删除功能"):
|
|||
|
|
row_taskDetail_index = self.taskDetailModel.index(row, 0, QModelIndex())
|
|||
|
|
taskInstructionId = self.taskDetailModel.data(row_taskDetail_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
if taskInstructionManager.delete(taskInstructionId):
|
|||
|
|
self.taskDetailModel.removeRow(row)
|
|||
|
|
|
|||
|
|
def updateTask(self):
|
|||
|
|
if self.taskModelBlockSignals == True:
|
|||
|
|
return
|
|||
|
|
if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_id_index = self.taskModel.index(row, 0, QModelIndex())
|
|||
|
|
row_name_index = self.taskModel.index(row, 2, QModelIndex())
|
|||
|
|
row_loop_index = self.taskModel.index(row, 3, QModelIndex())
|
|||
|
|
row_delay_index = self.taskModel.index(row, 4, QModelIndex())
|
|||
|
|
row_remark_index = self.taskModel.index(row, 5, QModelIndex())
|
|||
|
|
|
|||
|
|
name = self.taskModel.data(row_name_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
delay = self.taskModel.data(row_delay_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
loop = self.taskModel.data(row_loop_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
remark = self.taskModel.data(row_remark_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskParam = {
|
|||
|
|
"name": name,
|
|||
|
|
"delay": delay,
|
|||
|
|
"loop": loop,
|
|||
|
|
"remark": remark
|
|||
|
|
}
|
|||
|
|
result = taskManager.update(taskId, taskParam)
|
|||
|
|
|
|||
|
|
def updateTaskInstruction(self):
|
|||
|
|
if self.taskDetailModelBlockSignals == True:
|
|||
|
|
return
|
|||
|
|
if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows()) == 1:
|
|||
|
|
row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row()
|
|||
|
|
row_id_index = self.taskDetailModel.index(row, 0, QModelIndex())
|
|||
|
|
row_delay_index = self.taskDetailModel.index(row, 6, QModelIndex())
|
|||
|
|
row_loop_index = self.taskDetailModel.index(row, 7, QModelIndex())
|
|||
|
|
row_param_index = self.taskDetailModel.index(row, 8, QModelIndex())
|
|||
|
|
row_interfacenum_index = self.taskDetailModel.index(row, 9, QModelIndex())
|
|||
|
|
|
|||
|
|
delay = self.taskDetailModel.data(row_delay_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
loop = self.taskDetailModel.data(row_loop_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
param = self.taskDetailModel.data(row_param_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
interfaceIndex = self.taskDetailModel.data(row_interfacenum_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskInstanceId = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
|||
|
|
taskInstanceParam = {
|
|||
|
|
"delay": delay,
|
|||
|
|
"loop": loop,
|
|||
|
|
"target_param": param,
|
|||
|
|
"interface_index": interfaceIndex
|
|||
|
|
}
|
|||
|
|
result = taskInstructionManager.update(taskInstanceId, taskInstanceParam)
|
|||
|
|
|
|||
|
|
def setItemsEnable(self, enable):
|
|||
|
|
self.ui.pbInsertTask.setEnabled(enable)
|
|||
|
|
self.ui.pbDeleteTask.setEnabled(enable)
|
|||
|
|
self.ui.pbInsertInstruction.setEnabled(enable)
|
|||
|
|
if not enable:
|
|||
|
|
self.ui.tableViewTask.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
|||
|
|
else:
|
|||
|
|
self.ui.tableViewTask.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
|||
|
|
def clearTreeModel(self):
|
|||
|
|
try:
|
|||
|
|
for i in range(self.taskDetailDescriptionModel.rowCount()):
|
|||
|
|
self.taskDetailDescriptionModel.removeRow(0)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(e)
|
|||
|
|
#加载任务详情
|
|||
|
|
def loadTaskDetail(self, taskId):
|
|||
|
|
self.setItemsEnable(False)
|
|||
|
|
self.taskDetailModelBlockSignals = True
|
|||
|
|
self.taskDetailModel.clear()
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
self.loadPageTaskDetail(taskId, 0, 50)
|
|||
|
|
self.taskDetailModelBlockSignals = False
|
|||
|
|
self.setItemsEnable(True)
|
|||
|
|
self.batchOperation()
|
|||
|
|
|
|||
|
|
def loadPageTaskDetail(self, taskId, row, limit):
|
|||
|
|
QCoreApplication.processEvents()
|
|||
|
|
if taskId:
|
|||
|
|
taskInstructions = taskInstructionManager.getPageInfo(taskId,row, limit)
|
|||
|
|
if len(taskInstructions) > 0:
|
|||
|
|
for taskInstruction in taskInstructions:
|
|||
|
|
index = self.taskDetailModel.rowCount()
|
|||
|
|
self.taskDetailModel.setItem(index, 0, QStandardItem(str(taskInstruction["id"])))
|
|||
|
|
self.taskDetailModel.setItem(index, 1, QStandardItem(str(taskInstruction["task_id"])))
|
|||
|
|
name = ""
|
|||
|
|
type = ""
|
|||
|
|
devicename = ""
|
|||
|
|
dev_model_id = ""
|
|||
|
|
devinterface = []
|
|||
|
|
if taskInstruction["target_type"] == "instruction":
|
|||
|
|
instruction = instructionManager.getInfo(str(taskInstruction["target_id"]))
|
|||
|
|
if instruction:
|
|||
|
|
name = instruction["name"]
|
|||
|
|
type = instruction["type"]
|
|||
|
|
if instruction["type"] is not None and instruction["type"] in self.supportedTypes:
|
|||
|
|
type = self.supportedTypes[instruction["type"]]["name"]
|
|||
|
|
device_id = taskInstruction["device_id"]
|
|||
|
|
device = deviceManager.getInfo(device_id)
|
|||
|
|
if device != None:
|
|||
|
|
devicename = device["name"]
|
|||
|
|
dev_model_id = device["dev_model_id"]
|
|||
|
|
devinterface = device["interface"]
|
|||
|
|
elif taskInstruction["target_type"] == "task":
|
|||
|
|
task = taskManager.getInfo(taskInstruction["target_id"])
|
|||
|
|
if task != None:
|
|||
|
|
devicename = "任务"
|
|||
|
|
name = task["name"]
|
|||
|
|
self.taskDetailModel.setItem(index, 2, QStandardItem(str(index+1)))
|
|||
|
|
self.taskDetailModel.setItem(index, 3, QStandardItem(devicename))
|
|||
|
|
self.taskDetailModel.setItem(index, 4, QStandardItem(name))
|
|||
|
|
self.taskDetailModel.setItem(index, 5, QStandardItem(type))
|
|||
|
|
self.taskDetailModel.setItem(index, 6, QStandardItem(str(taskInstruction["delay"])))
|
|||
|
|
self.taskDetailModel.setItem(index, 7, QStandardItem(str(taskInstruction["loop"])))
|
|||
|
|
self.taskDetailModel.setItem(index, 8, QStandardItem(taskInstruction["target_param"]))
|
|||
|
|
self.taskDetailModel.setItem(index, 9, QStandardItem(""))
|
|||
|
|
self.taskDetailModel.setItem(index, 10, QStandardItem(str(taskInstruction["level"])))
|
|||
|
|
self.taskDetailModel.setItem(index, 11, QStandardItem(str(taskInstruction["target_id"])))
|
|||
|
|
self.setUnEditableStyle(self.taskDetailModel.item(index, 2))
|
|||
|
|
self.setDeviceStyle(self.taskDetailModel.item(index, 2), devicename)
|
|||
|
|
self.setUnEditableStyle(self.taskDetailModel.item(index, 3))
|
|||
|
|
self.setUnEditableStyle(self.taskDetailModel.item(index, 4))
|
|||
|
|
self.setUnEditableStyle(self.taskDetailModel.item(index, 5))
|
|||
|
|
|
|||
|
|
devModel = devModelManager.getInfo(dev_model_id)
|
|||
|
|
if devModel != None:
|
|||
|
|
attr_json_dict = devModel["attr"]
|
|||
|
|
devmodelInterfacetypes = {}
|
|||
|
|
if "interfaceType" in attr_json_dict:
|
|||
|
|
devmodelInterfacetypes = attr_json_dict["interfaceType"]
|
|||
|
|
if len(devmodelInterfacetypes) > 0:
|
|||
|
|
cmb = NoWheelComboBox()
|
|||
|
|
cmb.currentIndexChanged.connect(self.changeInterface)
|
|||
|
|
for devmodelInterfacetype in devmodelInterfacetypes:
|
|||
|
|
cmb.addItem(devmodelInterfacetype)
|
|||
|
|
interface_index = "interface_index" in taskInstruction and taskInstruction["interface_index"] or 0
|
|||
|
|
interface_index = interface_index != "" and interface_index or 0
|
|||
|
|
if interface_index < len(devmodelInterfacetypes):
|
|||
|
|
cmb.setCurrentIndex(interface_index)
|
|||
|
|
self.taskDetailModel.setItem(index, 9, QStandardItem(str(interface_index)))
|
|||
|
|
else:
|
|||
|
|
if len(devmodelInterfacetypes) > 0:
|
|||
|
|
cmb.setCurrentIndex(0)
|
|||
|
|
taskInstructionManager.update(str(taskInstruction["id"]), {"interface_index":0}) # 更新
|
|||
|
|
self.taskDetailModel.setItem(index, 9, QStandardItem("0"))
|
|||
|
|
self.ui.tableViewTaskDetail.setIndexWidget(self.taskDetailModel.index(index, 9), cmb)
|
|||
|
|
self.batchOperation()
|
|||
|
|
self.loadPageTaskDetail(taskId, row + limit,limit)
|
|||
|
|
else:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 切换接口
|
|||
|
|
def changeInterface(self,index):
|
|||
|
|
if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1:
|
|||
|
|
row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row()
|
|||
|
|
self.taskDetailModel.setItem(row, 9 , QStandardItem(str(index)))
|
|||
|
|
|
|||
|
|
def setTaskStyle(self,item,type):
|
|||
|
|
if type == "parent":
|
|||
|
|
item.setForeground(QColor(255, 255, 255))
|
|||
|
|
item.setBackground(QColor(240, 35, 35))
|
|||
|
|
elif type == "child":
|
|||
|
|
item.setForeground(QColor(0, 0, 0))
|
|||
|
|
item.setBackground(QColor(238, 191, 63))
|
|||
|
|
|
|||
|
|
def setDeviceStyle(self,item,device_name):
|
|||
|
|
if device_name == "":
|
|||
|
|
item.setBackground(QColor(229, 214, 223))
|
|||
|
|
else:
|
|||
|
|
item.setForeground(QColor(0, 0, 0))
|
|||
|
|
|
|||
|
|
|
|||
|
|
#设置不可编辑样式
|
|||
|
|
def setUnEditableStyle(self, item):
|
|||
|
|
item.setEditable(False)
|
|||
|
|
|
|||
|
|
def setSplitterStretchFactor(self):
|
|||
|
|
self.ui.splitter.setStretchFactor(0, 15)
|
|||
|
|
self.ui.splitter.setStretchFactor(1, 35)
|
|||
|
|
self.ui.splitter.setStretchFactor(2, 50)
|
|||
|
|
|
|||
|
|
# 批量操作
|
|||
|
|
def batchOperation(self):
|
|||
|
|
self.setAllHorizontalHeaderLabels()
|
|||
|
|
self.hideAllColumn()
|
|||
|
|
self.setAllColumnWidth()
|
|||
|
|
|
|||
|
|
# 批量设置标题
|
|||
|
|
def setAllHorizontalHeaderLabels(self):
|
|||
|
|
self.taskGroupModel.setHorizontalHeaderLabels(["ID","","名称"])
|
|||
|
|
self.taskModel.setHorizontalHeaderLabels(["ID","","名称", "循环次数", "间隔时间(ms)", "备注", "进度","组ID"])
|
|||
|
|
self.taskDetailModel.setHorizontalHeaderLabels(["ID","任务ID","","设备","名称", "类型", "间隔时间(ms)", "循环次数", "参数", "端口", "序号"])
|
|||
|
|
|
|||
|
|
# 隐藏指定列
|
|||
|
|
def hideAllColumn(self):
|
|||
|
|
self.ui.tableViewTask.setColumnHidden(0, True)
|
|||
|
|
self.ui.tableViewTask.setColumnHidden(1, True)
|
|||
|
|
self.ui.tableViewTask.setColumnHidden(7, True)
|
|||
|
|
self.ui.tableViewTask.setColumnHidden(8, True)
|
|||
|
|
self.ui.tableViewTaskGroup.setColumnHidden(0, True)
|
|||
|
|
self.ui.tableViewTaskGroup.setColumnHidden(1, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(0, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(1, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(10, True)
|
|||
|
|
self.ui.tableViewTaskDetail.setColumnHidden(11, True)
|
|||
|
|
|
|||
|
|
# 批量设置列宽
|
|||
|
|
def setAllColumnWidth(self):
|
|||
|
|
if self.taskGroupModel.rowCount() > 0:
|
|||
|
|
self.ui.tableViewTaskGroup.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
|||
|
|
self.ui.tableViewTaskGroup.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
if self.taskModel.rowCount() > 0:
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Interactive)
|
|||
|
|
if self.taskDetailModel.rowCount() > 0:
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Interactive)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(7, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(8, QHeaderView.ResizeMode.Stretch)
|
|||
|
|
self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(9, QHeaderView.ResizeMode.Interactive)
|
|||
|
|
|
|||
|
|
#加载全部被包含的子任务
|
|||
|
|
def loadAllSubTasks(self):
|
|||
|
|
self.subTasks = {}
|
|||
|
|
self.parentTasks = {}
|
|||
|
|
includingsubtasks = taskInstructionManager.getIncludingsubtasks()
|
|||
|
|
if len(includingsubtasks) > 0:
|
|||
|
|
for task in includingsubtasks:
|
|||
|
|
taskInfo = taskManager.getInfo(str(task["task_id"]))
|
|||
|
|
if taskInfo:
|
|||
|
|
taskName = taskInfo["name"]
|
|||
|
|
self.parentTasks[str(task["task_id"])] = True
|
|||
|
|
if str(task["target_id"]) in self.subTasks:
|
|||
|
|
if taskName not in self.subTasks[str(task["target_id"])]:
|
|||
|
|
self.subTasks[str(task["target_id"])].append(taskName)
|
|||
|
|
else:
|
|||
|
|
self.subTasks[str(task["target_id"])] = []
|
|||
|
|
self.subTasks[str(task["target_id"])].append(taskName)
|
|||
|
|
|
|||
|
|
# 加载队列组
|
|||
|
|
def loadTaskGroup(self):
|
|||
|
|
self.taskGroupModel.clear()
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
groups = taskGroupManager.getInfo()
|
|||
|
|
self.taskGroupModelBlockSignals = True
|
|||
|
|
if len(groups) > 0:
|
|||
|
|
for group in groups:
|
|||
|
|
index = self.taskGroupModel.rowCount()
|
|||
|
|
self.taskGroupModel.setItem(index, 0, QStandardItem(str(group["id"])))
|
|||
|
|
self.taskGroupModel.setItem(index, 1, QStandardItem(str(index+1)))
|
|||
|
|
self.taskGroupModel.setItem(index, 2, QStandardItem(group["name"]))
|
|||
|
|
self.setUnEditableStyle(self.taskGroupModel.item(index, 1))
|
|||
|
|
self.taskGroupModelBlockSignals = False
|
|||
|
|
self.batchOperation()
|
|||
|
|
|
|||
|
|
# 加载队列
|
|||
|
|
def loadTask(self):
|
|||
|
|
self.loadAllSubTasks()
|
|||
|
|
self.taskModel.clear()
|
|||
|
|
self.ui.textEditDescription.clear()
|
|||
|
|
self.clearTreeModel()
|
|||
|
|
tasks = taskManager.getGroupTask(self.current_groupId)
|
|||
|
|
self.taskModelBlockSignals = True
|
|||
|
|
if len(tasks) > 0:
|
|||
|
|
for task in tasks:
|
|||
|
|
index = self.taskModel.rowCount()
|
|||
|
|
progressItem = QxStandardItem('',self)
|
|||
|
|
progressItem.setData({'task_instruction_id': task["id"], 'name': task["name"]}, Qt.ItemDataRole.UserRole)
|
|||
|
|
self.taskModel.setItem(index, 0, QStandardItem(str(task["id"])))
|
|||
|
|
self.taskModel.setItem(index, 1, QStandardItem(str(index+1)))
|
|||
|
|
self.taskModel.setItem(index, 2, QStandardItem(task["name"]))
|
|||
|
|
self.taskModel.setItem(index, 3, QStandardItem(str(task["loop"])))
|
|||
|
|
self.taskModel.setItem(index, 4, QStandardItem(str(task["delay"])))
|
|||
|
|
self.taskModel.setItem(index, 5, QStandardItem(task["remark"]))
|
|||
|
|
self.taskModel.setItem(index, 6, progressItem)
|
|||
|
|
self.taskModel.setItem(index, 7, QStandardItem(str(task["group_id"])))
|
|||
|
|
self.taskModel.setItem(index, 8, QStandardItem("normal"))
|
|||
|
|
self.setUnEditableStyle(self.taskModel.item(index, 1))
|
|||
|
|
delegate = ProgressBarDelegate()
|
|||
|
|
self.ui.tableViewTask.setItemDelegateForColumn(6, delegate) # 为列索引为 1 的项设置自定义委托
|
|||
|
|
task_id = str(task["id"])
|
|||
|
|
|
|||
|
|
taskActuatorManager.updateProgress.connect(progressItem.updateProgress)
|
|||
|
|
if task_id in self.parentTasks:
|
|||
|
|
self.taskModel.setItem(index, 8, QStandardItem("parent"))
|
|||
|
|
if task_id in self.subTasks:
|
|||
|
|
self.taskModel.setItem(index, 8, QStandardItem("child"))
|
|||
|
|
self.taskModelBlockSignals = False
|
|||
|
|
self.batchOperation()
|