646 lines
21 KiB
C++
646 lines
21 KiB
C++
#include "TaskTreeModel.h"
|
|
#include <QBrush>
|
|
#include <QFont>
|
|
#include <QIcon>
|
|
|
|
// ==================== TaskTreeNode 实现 ====================
|
|
|
|
TaskTreeNode::TaskTreeNode(TaskTreeNode* parent)
|
|
: m_parent(parent)
|
|
{
|
|
}
|
|
|
|
TaskTreeNode::~TaskTreeNode()
|
|
{
|
|
qDeleteAll(m_children);
|
|
}
|
|
|
|
void TaskTreeNode::appendChild(TaskTreeNode* child)
|
|
{
|
|
m_children.append(child);
|
|
}
|
|
|
|
TaskTreeNode* TaskTreeNode::child(int row)
|
|
{
|
|
if (row < 0 || row >= m_children.size())
|
|
return nullptr;
|
|
return m_children.at(row);
|
|
}
|
|
|
|
int TaskTreeNode::childCount() const
|
|
{
|
|
return m_children.size();
|
|
}
|
|
|
|
int TaskTreeNode::row() const
|
|
{
|
|
if (m_parent) {
|
|
return m_parent->m_children.indexOf(const_cast<TaskTreeNode*>(this));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
TaskTreeNode* TaskTreeNode::parentNode()
|
|
{
|
|
return m_parent;
|
|
}
|
|
|
|
// ==================== TaskTreeModel 实现 ====================
|
|
|
|
TaskTreeModel::TaskTreeModel(QObject* parent)
|
|
: QAbstractItemModel(parent)
|
|
, m_rootNode(new TaskTreeNode())
|
|
, m_countdownTimer(new QTimer(this))
|
|
{
|
|
m_rootNode->nodeType = TreeNodeType::Root;
|
|
m_countdownTimer->setInterval(1000);
|
|
connect(m_countdownTimer, &QTimer::timeout, this, &TaskTreeModel::onCountdownTimerTimeout);
|
|
}
|
|
|
|
TaskTreeModel::~TaskTreeModel()
|
|
{
|
|
m_countdownTimer->stop();
|
|
delete m_rootNode;
|
|
}
|
|
|
|
QModelIndex TaskTreeModel::index(int row, int column, const QModelIndex& parent) const
|
|
{
|
|
if (!hasIndex(row, column, parent))
|
|
return QModelIndex();
|
|
|
|
TaskTreeNode* parentNode;
|
|
if (!parent.isValid())
|
|
parentNode = m_rootNode;
|
|
else
|
|
parentNode = static_cast<TaskTreeNode*>(parent.internalPointer());
|
|
|
|
TaskTreeNode* childNode = parentNode->child(row);
|
|
if (childNode)
|
|
return createIndex(row, column, childNode);
|
|
|
|
return QModelIndex();
|
|
}
|
|
|
|
QModelIndex TaskTreeModel::parent(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return QModelIndex();
|
|
|
|
TaskTreeNode* childNode = static_cast<TaskTreeNode*>(index.internalPointer());
|
|
TaskTreeNode* parentNode = childNode->parentNode();
|
|
|
|
if (parentNode == m_rootNode)
|
|
return QModelIndex();
|
|
|
|
return createIndex(parentNode->row(), 0, parentNode);
|
|
}
|
|
|
|
int TaskTreeModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
TaskTreeNode* parentNode;
|
|
if (!parent.isValid())
|
|
parentNode = m_rootNode;
|
|
else
|
|
parentNode = static_cast<TaskTreeNode*>(parent.internalPointer());
|
|
|
|
return parentNode->childCount();
|
|
}
|
|
|
|
int TaskTreeModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
Q_UNUSED(parent)
|
|
return ColumnCount;
|
|
}
|
|
|
|
QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
TaskTreeNode* node = static_cast<TaskTreeNode*>(index.internalPointer());
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
|
const TimedTask& task = *node->taskData;
|
|
switch (index.column()) {
|
|
case ColName:
|
|
return QString::fromLocal8Bit("定时任务 %1").arg(task.id);
|
|
case ColScheduledTime:
|
|
return task.scheduledTime.toString("yyyy-MM-dd HH:mm:ss");
|
|
case ColCountdown: {
|
|
if (task.status == TaskStatus::Finished || task.status == TaskStatus::Running)
|
|
{
|
|
return QString::fromLocal8Bit("0");
|
|
}
|
|
qint64 seconds = QDateTime::currentDateTime().secsTo(task.scheduledTime);
|
|
if (seconds < 0)
|
|
{
|
|
return QString::fromLocal8Bit("已超时");
|
|
}
|
|
return formatCountdown(seconds);
|
|
}
|
|
case ColStartTime:
|
|
return task.startTime.isValid() ?
|
|
task.startTime.toString("HH:mm:ss") : "-";
|
|
case ColEndTime:
|
|
return task.endTime.isValid() ?
|
|
task.endTime.toString("HH:mm:ss") : "-";
|
|
case ColDuration:
|
|
return formatDuration(task.durationMinutes);
|
|
case ColEstimatedDuration:
|
|
return formatDuration(task.estimatedDurationMinutes);
|
|
case ColStatus:
|
|
return statusToString(task.status);
|
|
case ColProgress: {
|
|
int finished = 0;
|
|
for (const auto& sub : task.subTasks) {
|
|
if (sub.status == TaskStatus::Finished) finished++;
|
|
}
|
|
return QString("%1/%2").arg(finished).arg(task.subTasks.size());
|
|
}
|
|
case ColPath:
|
|
return task.savePath;
|
|
}
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
|
const SubTask& subTask = *node->subTaskData;
|
|
switch (index.column()) {
|
|
case ColName:
|
|
return subTaskTypeToString(subTask.type);
|
|
case ColScheduledTime:
|
|
return "-";
|
|
case ColCountdown:
|
|
return "-";
|
|
case ColStartTime:
|
|
return subTask.startTime.isValid() ?
|
|
subTask.startTime.toString("HH:mm:ss") : "-";
|
|
case ColEndTime:
|
|
return subTask.endTime.isValid() ?
|
|
subTask.endTime.toString("HH:mm:ss") : "-";
|
|
case ColDuration:
|
|
return formatDuration(subTask.durationMinutes);
|
|
case ColEstimatedDuration:
|
|
return formatDuration(subTask.estimatedDurationMinutes);
|
|
case ColStatus:
|
|
return statusToString(subTask.status);
|
|
case ColProgress:
|
|
return "-";
|
|
case ColPath:
|
|
return "-";
|
|
}
|
|
}
|
|
}
|
|
else if (role == Qt::BackgroundRole) {
|
|
TaskStatus status = TaskStatus::Waiting;
|
|
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
|
status = node->taskData->status;
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
|
status = node->subTaskData->status;
|
|
}
|
|
return QBrush(statusColor(status));
|
|
}
|
|
else if (role == Qt::ForegroundRole) {
|
|
TaskStatus status = TaskStatus::Waiting;
|
|
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
|
status = node->taskData->status;
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
|
status = node->subTaskData->status;
|
|
}
|
|
if (status == TaskStatus::Running) {
|
|
return QBrush(QColor(0, 100, 0)); // 深绿色文字
|
|
}
|
|
}
|
|
else if (role == Qt::FontRole) {
|
|
QFont font;
|
|
if (node->nodeType == TreeNodeType::Task) {
|
|
font.setBold(true);
|
|
if (node->taskData && node->taskData->status == TaskStatus::Running) {
|
|
font.setItalic(true);
|
|
}
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask) {
|
|
if (node->subTaskData && node->subTaskData->status == TaskStatus::Running) {
|
|
font.setBold(true);
|
|
}
|
|
}
|
|
return font;
|
|
}
|
|
else if (role == Qt::DecorationRole && index.column() == ColName) {
|
|
if (node->nodeType == TreeNodeType::Task) {
|
|
// 可以返回任务图标
|
|
// return QIcon(":/icons/task.png");
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
|
// 根据子任务类型返回不同图标
|
|
switch (node->subTaskData->type) {
|
|
case SubTaskType::HyperSpectual400_1000nm:
|
|
case SubTaskType::HyperSpectual1000_1700nm:
|
|
// return QIcon(":/icons/hyperspectral.png");
|
|
break;
|
|
case SubTaskType::SingleLensReflex:
|
|
// return QIcon(":/icons/camera.png");
|
|
break;
|
|
case SubTaskType::DepthCamera:
|
|
// return QIcon(":/icons/depth.png");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (role == Qt::TextAlignmentRole) {
|
|
if (index.column() == ColName || index.column() == ColPath) {
|
|
return static_cast<int>(Qt::AlignLeft | Qt::AlignVCenter);
|
|
}
|
|
return Qt::AlignCenter;
|
|
}
|
|
else if (role == Qt::ToolTipRole) {
|
|
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
|
return QString::fromLocal8Bit("任务ID: %1\n保存路径: %2\n预热时间: %3 分钟")
|
|
.arg(node->taskData->id)
|
|
.arg(node->taskData->savePath)
|
|
.arg(node->taskData->HalogenLampPreheatingTime_Minute);
|
|
}
|
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
|
QString tip = QString::fromLocal8Bit("类型: %1\n路径文件: %2")
|
|
.arg(subTaskTypeToString(node->subTaskData->type))
|
|
.arg(node->subTaskData->pathLineFilePath);
|
|
|
|
if (node->subTaskData->type == SubTaskType::HyperSpectual400_1000nm ||
|
|
node->subTaskData->type == SubTaskType::HyperSpectual1000_1700nm) {
|
|
tip += QString::fromLocal8Bit("\n帧率: %1\n曝光时间: %2")
|
|
.arg(node->subTaskData->frameRate)
|
|
.arg(node->subTaskData->exposureTime);
|
|
}
|
|
return tip;
|
|
}
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant TaskTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
|
|
return QVariant();
|
|
|
|
switch (section) {
|
|
case ColName: return QString::fromLocal8Bit("名称");
|
|
case ColScheduledTime: return QString::fromLocal8Bit("计划时间");
|
|
case ColCountdown: return QString::fromLocal8Bit("倒计时");
|
|
case ColStartTime: return QString::fromLocal8Bit("开始时间");
|
|
case ColEndTime: return QString::fromLocal8Bit("结束时间");
|
|
case ColDuration: return QString::fromLocal8Bit("耗时");
|
|
case ColEstimatedDuration: return QString::fromLocal8Bit("预测耗时");
|
|
case ColStatus: return QString::fromLocal8Bit("状态");
|
|
case ColProgress: return QString::fromLocal8Bit("进度");
|
|
case ColPath: return QString::fromLocal8Bit("路径");
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags TaskTreeModel::flags(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return Qt::NoItemFlags;
|
|
|
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
}
|
|
|
|
void TaskTreeModel::setTasks(const QVector<TimedTask>& tasks)
|
|
{
|
|
m_countdownTimer->stop();
|
|
|
|
beginResetModel();
|
|
|
|
m_tasks = tasks;
|
|
clearTree();
|
|
setupModelData();
|
|
|
|
endResetModel();
|
|
|
|
m_countdownTimer->start();
|
|
}
|
|
|
|
void TaskTreeModel::setupModelData()
|
|
{
|
|
for (int i = 0; i < m_tasks.size(); ++i) {
|
|
TimedTask& task = m_tasks[i];
|
|
|
|
// 创建任务节点
|
|
TaskTreeNode* taskNode = new TaskTreeNode(m_rootNode);
|
|
taskNode->nodeType = TreeNodeType::Task;
|
|
taskNode->taskId = task.id;
|
|
taskNode->taskData = &task;
|
|
m_rootNode->appendChild(taskNode);
|
|
|
|
// 为每个子任务创建节点
|
|
for (int j = 0; j < task.subTasks.size(); ++j) {
|
|
SubTask& subTask = task.subTasks[j];
|
|
|
|
TaskTreeNode* subTaskNode = new TaskTreeNode(taskNode);
|
|
subTaskNode->nodeType = TreeNodeType::SubTask;
|
|
subTaskNode->taskId = task.id;
|
|
subTaskNode->subTaskIndex = j;
|
|
subTaskNode->subTaskData = &subTask;
|
|
taskNode->appendChild(subTaskNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskTreeModel::clearTree()
|
|
{
|
|
// 删除所有子节点
|
|
while (m_rootNode->childCount() > 0) {
|
|
delete m_rootNode->child(0);
|
|
}
|
|
}
|
|
|
|
void TaskTreeModel::updateTask(const TimedTask& task)
|
|
{
|
|
int dataIndex = findTaskDataIndex(task.id);
|
|
if (dataIndex < 0) return;
|
|
|
|
// 更新数据
|
|
m_tasks[dataIndex] = task;
|
|
|
|
// 重新设置指针(因为数据被复制了)
|
|
TaskTreeNode* taskNode = findTaskNode(task.id);
|
|
if (taskNode) {
|
|
taskNode->taskData = &m_tasks[dataIndex];
|
|
|
|
// 更新子任务指针
|
|
for (int i = 0; i < taskNode->childCount() && i < m_tasks[dataIndex].subTasks.size(); ++i) {
|
|
TaskTreeNode* subNode = taskNode->child(i);
|
|
if (subNode) {
|
|
subNode->subTaskData = &m_tasks[dataIndex].subTasks[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// 通知视图更新任务行
|
|
QModelIndex taskIndex = getTaskIndex(task.id);
|
|
if (taskIndex.isValid()) {
|
|
QModelIndex topLeft = index(taskIndex.row(), 0, taskIndex.parent());
|
|
QModelIndex bottomRight = index(taskIndex.row(), ColumnCount - 1, taskIndex.parent());
|
|
emit dataChanged(topLeft, bottomRight);
|
|
|
|
// 更新所有子任务行
|
|
int subCount = rowCount(taskIndex);
|
|
if (subCount > 0) {
|
|
QModelIndex subTopLeft = index(0, 0, taskIndex);
|
|
QModelIndex subBottomRight = index(subCount - 1, ColumnCount - 1, taskIndex);
|
|
emit dataChanged(subTopLeft, subBottomRight);
|
|
}
|
|
}
|
|
|
|
emit taskUpdated(task.id);
|
|
}
|
|
|
|
void TaskTreeModel::updateSubTask(int taskId, int subTaskIndex, const SubTask& subTask)
|
|
{
|
|
int dataIndex = findTaskDataIndex(taskId);
|
|
if (dataIndex < 0 || subTaskIndex >= m_tasks[dataIndex].subTasks.size())
|
|
return;
|
|
|
|
m_tasks[dataIndex].subTasks[subTaskIndex] = subTask;
|
|
|
|
// 重新设置指针
|
|
TaskTreeNode* subNode = findSubTaskNode(taskId, subTaskIndex);
|
|
if (subNode) {
|
|
subNode->subTaskData = &m_tasks[dataIndex].subTasks[subTaskIndex];
|
|
}
|
|
|
|
QModelIndex subTaskModelIndex = getSubTaskIndex(taskId, subTaskIndex);
|
|
if (subTaskModelIndex.isValid()) {
|
|
QModelIndex topLeft = index(subTaskModelIndex.row(), 0, subTaskModelIndex.parent());
|
|
QModelIndex bottomRight = index(subTaskModelIndex.row(), ColumnCount - 1, subTaskModelIndex.parent());
|
|
emit dataChanged(topLeft, bottomRight);
|
|
}
|
|
|
|
// 同时更新父任务的进度显示
|
|
QModelIndex taskIndex = getTaskIndex(taskId);
|
|
if (taskIndex.isValid()) {
|
|
QModelIndex progressIndex = index(taskIndex.row(), ColProgress, taskIndex.parent());
|
|
emit dataChanged(progressIndex, progressIndex);
|
|
}
|
|
|
|
emit subTaskUpdated(taskId, subTaskIndex);
|
|
}
|
|
|
|
void TaskTreeModel::setTaskAndSubtaskStatus(int taskId, TaskStatus status)
|
|
{
|
|
int dataIndex = findTaskDataIndex(taskId);
|
|
if (dataIndex < 0) return;
|
|
|
|
updateTaskStatus(taskId, status);
|
|
|
|
for (size_t i = 0; i < m_tasks[dataIndex].subTaskCount(); i++)
|
|
{
|
|
updateSubTaskStatus(taskId, i, status);
|
|
}
|
|
}
|
|
|
|
void TaskTreeModel::updateTaskStatus(int taskId, TaskStatus status)
|
|
{
|
|
int dataIndex = findTaskDataIndex(taskId);
|
|
if (dataIndex < 0) return;
|
|
|
|
m_tasks[dataIndex].status = status;
|
|
|
|
QModelIndex taskIndex = getTaskIndex(taskId);
|
|
if (taskIndex.isValid()) {
|
|
QModelIndex topLeft = index(taskIndex.row(), 0, taskIndex.parent());
|
|
QModelIndex bottomRight = index(taskIndex.row(), ColumnCount - 1, taskIndex.parent());
|
|
emit dataChanged(topLeft, bottomRight);
|
|
}
|
|
}
|
|
|
|
void TaskTreeModel::updateSubTaskStatusAndProgress(int taskId, int subTaskIndex, TaskStatus status)
|
|
{
|
|
updateSubTaskStatus(taskId, subTaskIndex, status);
|
|
updateProgress(taskId);
|
|
}
|
|
|
|
void TaskTreeModel::updateSubTaskStatus(int taskId, int subTaskIndex, TaskStatus status)
|
|
{
|
|
int dataIndex = findTaskDataIndex(taskId);
|
|
if (dataIndex < 0 || subTaskIndex >= m_tasks[dataIndex].subTasks.size())
|
|
return;
|
|
|
|
SubTask& subTask = m_tasks[dataIndex].subTasks[subTaskIndex];
|
|
subTask.status = status;
|
|
|
|
QModelIndex subTaskModelIndex = getSubTaskIndex(taskId, subTaskIndex);
|
|
if (subTaskModelIndex.isValid()) {
|
|
QModelIndex topLeft = index(subTaskModelIndex.row(), 0, subTaskModelIndex.parent());
|
|
QModelIndex bottomRight = index(subTaskModelIndex.row(), ColumnCount - 1, subTaskModelIndex.parent());
|
|
emit dataChanged(topLeft, bottomRight);
|
|
}
|
|
}
|
|
|
|
void TaskTreeModel::updateProgress(int taskId)
|
|
{
|
|
// 更新父任务进度
|
|
QModelIndex taskIndex = getTaskIndex(taskId);
|
|
if (taskIndex.isValid()) {
|
|
QModelIndex progressIndex = index(taskIndex.row(), ColProgress, taskIndex.parent());
|
|
emit dataChanged(progressIndex, progressIndex);
|
|
}
|
|
}
|
|
|
|
TimedTask* TaskTreeModel::getTask(int taskId)
|
|
{
|
|
int idx = findTaskDataIndex(taskId);
|
|
if (idx >= 0) {
|
|
return &m_tasks[idx];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
SubTask* TaskTreeModel::getSubTask(int taskId, int subTaskIndex)
|
|
{
|
|
TimedTask* task = getTask(taskId);
|
|
if (task && subTaskIndex >= 0 && subTaskIndex < task->subTasks.size()) {
|
|
return &task->subTasks[subTaskIndex];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QModelIndex TaskTreeModel::getTaskIndex(int taskId) const
|
|
{
|
|
for (int i = 0; i < m_rootNode->childCount(); ++i) {
|
|
TaskTreeNode* node = m_rootNode->child(i);
|
|
if (node && node->taskId == taskId) {
|
|
return createIndex(i, 0, node);
|
|
}
|
|
}
|
|
return QModelIndex();
|
|
}
|
|
|
|
QModelIndex TaskTreeModel::getSubTaskIndex(int taskId, int subTaskIndex) const
|
|
{
|
|
TaskTreeNode* taskNode = findTaskNode(taskId);
|
|
if (taskNode && subTaskIndex < taskNode->childCount()) {
|
|
TaskTreeNode* subNode = taskNode->child(subTaskIndex);
|
|
if (subNode) {
|
|
return createIndex(subTaskIndex, 0, subNode);
|
|
}
|
|
}
|
|
return QModelIndex();
|
|
}
|
|
|
|
TaskTreeNode* TaskTreeModel::findTaskNode(int taskId) const
|
|
{
|
|
for (int i = 0; i < m_rootNode->childCount(); ++i) {
|
|
TaskTreeNode* node = m_rootNode->child(i);
|
|
if (node && node->taskId == taskId) {
|
|
return node;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
TaskTreeNode* TaskTreeModel::findSubTaskNode(int taskId, int subTaskIndex) const
|
|
{
|
|
TaskTreeNode* taskNode = findTaskNode(taskId);
|
|
if (taskNode && subTaskIndex < taskNode->childCount()) {
|
|
return taskNode->child(subTaskIndex);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int TaskTreeModel::findTaskDataIndex(int taskId) const
|
|
{
|
|
for (int i = 0; i < m_tasks.size(); ++i) {
|
|
if (m_tasks[i].id == taskId) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
QString TaskTreeModel::statusToString(TaskStatus status) const
|
|
{
|
|
switch (status) {
|
|
case TaskStatus::default: return QString::fromLocal8Bit("未调度");
|
|
case TaskStatus::Waiting: return QString::fromLocal8Bit("等待中");
|
|
case TaskStatus::Running: return QString::fromLocal8Bit("运行中");
|
|
case TaskStatus::Finished: return QString::fromLocal8Bit("已完成");
|
|
case TaskStatus::Skiped: return QString::fromLocal8Bit("已跳过");
|
|
case TaskStatus::Timeout: return QString::fromLocal8Bit("超时");
|
|
}
|
|
return "";
|
|
}
|
|
|
|
QString TaskTreeModel::subTaskTypeToString(SubTaskType type) const
|
|
{
|
|
switch (type) {
|
|
case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm");
|
|
case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm");
|
|
case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机");
|
|
case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机");
|
|
}
|
|
return "未知类型";
|
|
}
|
|
|
|
QString TaskTreeModel::formatDuration(double minutes) const
|
|
{
|
|
if (minutes <= 0) return "-";
|
|
|
|
int hours = static_cast<int>(minutes) / 60;
|
|
int mins = static_cast<int>(minutes) % 60;
|
|
int secs = static_cast<int>((minutes - static_cast<int>(minutes)) * 60);
|
|
|
|
if (hours > 0) {
|
|
return QString::fromLocal8Bit(("%1时%2分%3秒")).arg(hours).arg(mins).arg(secs);
|
|
}
|
|
else if (mins > 0) {
|
|
return QString::fromLocal8Bit(("%1分%2秒")).arg(mins).arg(secs);
|
|
}
|
|
else {
|
|
return QString::fromLocal8Bit(("%1秒")).arg(secs);
|
|
}
|
|
}
|
|
|
|
QColor TaskTreeModel::statusColor(TaskStatus status) const
|
|
{
|
|
switch (status) {
|
|
case TaskStatus::Waiting: return QColor(255, 255, 230); // 浅黄
|
|
case TaskStatus::Running: return QColor(200, 255, 200); // 浅绿
|
|
case TaskStatus::Finished: return QColor(220, 220, 255); // 浅蓝
|
|
case TaskStatus::Skiped: return QColor(220, 220, 220); // 浅灰
|
|
}
|
|
return QColor(255, 255, 255);
|
|
}
|
|
|
|
QString TaskTreeModel::formatCountdown(qint64 seconds) const
|
|
{
|
|
if (seconds < 0) {
|
|
return QString::fromLocal8Bit("已超时");
|
|
}
|
|
|
|
int hours = static_cast<int>(seconds) / 3600;
|
|
int mins = (static_cast<int>(seconds) % 3600) / 60;
|
|
int secs = static_cast<int>(seconds) % 60;
|
|
|
|
return QString("%1:%2:%3")
|
|
.arg(hours, 2, 10, QChar('0'))
|
|
.arg(mins, 2, 10, QChar('0'))
|
|
.arg(secs, 2, 10, QChar('0'));
|
|
}
|
|
|
|
void TaskTreeModel::onCountdownTimerTimeout()
|
|
{
|
|
for (int i = 0; i < m_tasks.size(); ++i)
|
|
{
|
|
const TimedTask& task = m_tasks[i];
|
|
QModelIndex taskIndex = getTaskIndex(task.id);
|
|
if (taskIndex.isValid())
|
|
{
|
|
QModelIndex countdownIndex = index(taskIndex.row(), ColCountdown, taskIndex.parent());
|
|
emit dataChanged(countdownIndex, countdownIndex);
|
|
}
|
|
}
|
|
}
|