Files
CalibratorLauncher/procedure/procedureengine.cpp
2026-01-02 19:20:35 +09:00

866 lines
21 KiB
C++

#include "procedureengine.h"
#include "procedureparser.h"
#include <QDebug>
#include <QFile>
#include <QTimer>
#include <QRegularExpression>
// =============================================================================
// 單例實現
// =============================================================================
ProcedureEngine *ProcedureEngine::s_instance = nullptr;
ProcedureEngine *ProcedureEngine::instance()
{
if (!s_instance)
{
s_instance = new ProcedureEngine();
}
return s_instance;
}
ProcedureEngine::ProcedureEngine(QObject *parent)
: QObject(parent), m_parser(new ProcedureParser(this)), m_status(ProcedureStatus::Idle), m_executionTimer(new QTimer(this))
{
connect(m_executionTimer, &QTimer::timeout, this, &ProcedureEngine::onExecutionTimeout);
}
ProcedureEngine::~ProcedureEngine()
{
}
// =============================================================================
// 配置載入
// =============================================================================
bool ProcedureEngine::loadProcedure(const QString &configPath)
{
if (m_status == ProcedureStatus::Running || m_status == ProcedureStatus::Paused)
{
qWarning() << "程序正在執行中,無法載入新配置";
return false;
}
// 檢查文件是否存在
if (!QFile::exists(configPath))
{
emit errorOccurred(QString("配置文件不存在: %1").arg(configPath));
return false;
}
// 解析配置
if (!m_parser->loadConfig(configPath))
{
emit errorOccurred(QString("配置文件解析失敗: %1").arg(configPath));
return false;
}
m_config = m_parser->parseProcedureConfig();
// 驗證配置
if (!m_parser->validateConfig())
{
QStringList errors = m_parser->getValidationErrors();
emit errorOccurred(QString("配置驗證失敗:\n%1").arg(errors.join("\n")));
return false;
}
// 初始化執行上下文
resetExecutionContext();
m_configPath = configPath;
setStatus(ProcedureStatus::Loaded);
emit procedureLoaded(m_config.procedureName);
qDebug() << "程序載入成功:" << m_config.procedureName;
qDebug() << " - 任務組數量:" << m_config.testTaskGroups.size();
qDebug() << " - 活動序列數量:" << m_config.activitySequence.size();
return true;
}
void ProcedureEngine::resetExecutionContext()
{
m_context = ExecutionContext();
m_context.currentActivityIndex = -1;
m_context.currentStageIndex = -1;
m_context.currentActionIndex = -1;
m_context.loopIteration = 0;
m_context.startTime = QDateTime();
}
// =============================================================================
// 程序控制
// =============================================================================
void ProcedureEngine::startProcedure()
{
if (m_status != ProcedureStatus::Loaded && m_status != ProcedureStatus::Completed)
{
qWarning() << "程序狀態不正確,無法啟動";
return;
}
resetExecutionContext();
m_context.startTime = QDateTime::currentDateTime();
setStatus(ProcedureStatus::Running);
emit procedureStarted();
// 移動到第一個活動
moveToFirstActivity();
}
void ProcedureEngine::pauseProcedure()
{
if (m_status != ProcedureStatus::Running)
{
return;
}
m_executionTimer->stop();
setStatus(ProcedureStatus::Paused);
emit procedurePaused();
}
void ProcedureEngine::resumeProcedure()
{
if (m_status != ProcedureStatus::Paused)
{
return;
}
setStatus(ProcedureStatus::Running);
emit procedureResumed();
// 繼續執行當前動作
executeCurrentAction();
}
void ProcedureEngine::stopProcedure()
{
if (m_status == ProcedureStatus::Idle || m_status == ProcedureStatus::Loaded)
{
return;
}
m_executionTimer->stop();
setStatus(ProcedureStatus::Stopped);
emit procedureStopped();
}
void ProcedureEngine::resetProcedure()
{
stopProcedure();
resetExecutionContext();
setStatus(ProcedureStatus::Loaded);
// 清除所有表格數據
m_tableData.clear();
}
// =============================================================================
// 活動導航
// =============================================================================
void ProcedureEngine::moveToFirstActivity()
{
if (m_config.activitySequence.isEmpty())
{
completeProcedure();
return;
}
m_context.currentActivityIndex = 0;
m_context.currentStageIndex = -1;
m_context.currentActionIndex = -1;
enterCurrentActivity();
}
bool ProcedureEngine::moveToNextActivity()
{
if (m_status != ProcedureStatus::Running)
{
return false;
}
int nextIndex = m_context.currentActivityIndex + 1;
if (nextIndex >= m_config.activitySequence.size())
{
// 沒有更多活動
completeProcedure();
return false;
}
m_context.currentActivityIndex = nextIndex;
m_context.currentStageIndex = -1;
m_context.currentActionIndex = -1;
enterCurrentActivity();
return true;
}
bool ProcedureEngine::moveToPreviousActivity()
{
if (m_status != ProcedureStatus::Running && m_status != ProcedureStatus::Paused)
{
return false;
}
int prevIndex = m_context.currentActivityIndex - 1;
if (prevIndex < 0)
{
return false;
}
m_context.currentActivityIndex = prevIndex;
m_context.currentStageIndex = -1;
m_context.currentActionIndex = -1;
enterCurrentActivity();
return true;
}
bool ProcedureEngine::jumpToActivity(int index)
{
if (index < 0 || index >= m_config.activitySequence.size())
{
return false;
}
m_context.currentActivityIndex = index;
m_context.currentStageIndex = -1;
m_context.currentActionIndex = -1;
enterCurrentActivity();
return true;
}
void ProcedureEngine::enterCurrentActivity()
{
if (m_context.currentActivityIndex < 0 ||
m_context.currentActivityIndex >= m_config.activitySequence.size())
{
return;
}
const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex];
qDebug() << "進入活動:" << step.name << "(" << step.ref << ")";
emit activityStarted(m_context.currentActivityIndex, step);
if (step.type == ActivityType::TEST_TASK_GROUP)
{
// 開始執行任務組
startTaskGroupExecution(step.ref);
}
else if (step.type == ActivityType::RESULT_DISPLAY)
{
// 顯示結果
displayResult(step.ref);
}
}
// =============================================================================
// 任務組執行
// =============================================================================
void ProcedureEngine::startTaskGroupExecution(const QString &taskGroupRef)
{
if (!m_config.testTaskGroups.contains(taskGroupRef))
{
emit errorOccurred(QString("找不到任務組: %1").arg(taskGroupRef));
return;
}
const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef];
qDebug() << "開始執行任務組:" << taskGroup.name;
qDebug() << " - 階段數量:" << taskGroup.stages.size();
emit taskGroupStarted(taskGroupRef, taskGroup.name);
// 初始化表格
for (const QString &tableRef : taskGroup.tableRefs)
{
initializeTable(tableRef);
}
// 移動到第一個階段
if (!taskGroup.stages.isEmpty())
{
m_context.currentStageIndex = 0;
m_context.currentActionIndex = -1;
enterCurrentStage(taskGroupRef);
}
else
{
// 沒有階段,完成任務組
completeTaskGroup(taskGroupRef);
}
}
void ProcedureEngine::enterCurrentStage(const QString &taskGroupRef)
{
if (!m_config.testTaskGroups.contains(taskGroupRef))
{
return;
}
const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef];
if (m_context.currentStageIndex < 0 ||
m_context.currentStageIndex >= taskGroup.stages.size())
{
completeTaskGroup(taskGroupRef);
return;
}
const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex];
qDebug() << "進入階段:" << stage.name;
emit stageStarted(m_context.currentStageIndex, stage.name);
// 檢查跳過條件
if (!stage.skipCondition.isEmpty() && evaluateCondition(stage.skipCondition))
{
qDebug() << "階段被跳過:" << stage.name;
moveToNextStage(taskGroupRef);
return;
}
// 移動到第一個動作
if (!stage.actions.isEmpty())
{
m_context.currentActionIndex = 0;
executeCurrentAction();
}
else
{
// 沒有動作,移動到下一個階段
moveToNextStage(taskGroupRef);
}
}
void ProcedureEngine::moveToNextStage(const QString &taskGroupRef)
{
if (!m_config.testTaskGroups.contains(taskGroupRef))
{
return;
}
const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef];
int nextStageIndex = m_context.currentStageIndex + 1;
if (nextStageIndex >= taskGroup.stages.size())
{
// 檢查循環
m_context.loopIteration++;
if (m_context.loopIteration < taskGroup.loopCount)
{
// 繼續下一輪
m_context.currentStageIndex = 0;
m_context.currentActionIndex = -1;
enterCurrentStage(taskGroupRef);
}
else
{
// 完成任務組
completeTaskGroup(taskGroupRef);
}
return;
}
m_context.currentStageIndex = nextStageIndex;
m_context.currentActionIndex = -1;
enterCurrentStage(taskGroupRef);
}
void ProcedureEngine::completeTaskGroup(const QString &taskGroupRef)
{
qDebug() << "任務組完成:" << taskGroupRef;
m_context.loopIteration = 0;
emit taskGroupCompleted(taskGroupRef);
// 自動移動到下一個活動(如果處於運行狀態)
if (m_status == ProcedureStatus::Running)
{
// 使用延遲以允許UI更新
QTimer::singleShot(100, this, [this]()
{ moveToNextActivity(); });
}
}
// =============================================================================
// 動作執行
// =============================================================================
void ProcedureEngine::executeCurrentAction()
{
if (m_status != ProcedureStatus::Running)
{
return;
}
const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex];
if (step.type != ActivityType::TEST_TASK_GROUP)
{
return;
}
if (!m_config.testTaskGroups.contains(step.ref))
{
return;
}
const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref];
if (m_context.currentStageIndex < 0 ||
m_context.currentStageIndex >= taskGroup.stages.size())
{
return;
}
const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex];
if (m_context.currentActionIndex < 0 ||
m_context.currentActionIndex >= stage.actions.size())
{
// 階段動作執行完畢,移動到下一個階段
emit stageCompleted(m_context.currentStageIndex);
moveToNextStage(step.ref);
return;
}
const TestAction &action = stage.actions[m_context.currentActionIndex];
qDebug() << "執行動作:" << action.actionId << "-" << action.functionName;
emit actionStarted(m_context.currentActionIndex, action.actionId);
// 設置超時
if (action.timeout > 0)
{
m_executionTimer->start(action.timeout);
}
// 請求執行動作(通過信號通知外部執行)
emit executeActionRequested(action);
}
void ProcedureEngine::onActionCompleted(const QString &actionId, const QVariantMap &results)
{
m_executionTimer->stop();
qDebug() << "動作完成:" << actionId;
emit actionCompleted(m_context.currentActionIndex, actionId, results);
// 處理結果(寫入表格等)
processActionResults(actionId, results);
// 移動到下一個動作
moveToNextAction();
}
void ProcedureEngine::onActionFailed(const QString &actionId, const QString &error)
{
m_executionTimer->stop();
qWarning() << "動作執行失敗:" << actionId << "-" << error;
emit actionFailed(m_context.currentActionIndex, actionId, error);
// 根據配置決定是否繼續
// TODO: 可配置的錯誤處理策略
moveToNextAction();
}
void ProcedureEngine::moveToNextAction()
{
if (m_status != ProcedureStatus::Running)
{
return;
}
m_context.currentActionIndex++;
executeCurrentAction();
}
void ProcedureEngine::onExecutionTimeout()
{
qWarning() << "動作執行超時";
const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex];
if (step.type == ActivityType::TEST_TASK_GROUP &&
m_config.testTaskGroups.contains(step.ref))
{
const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref];
if (m_context.currentStageIndex >= 0 &&
m_context.currentStageIndex < taskGroup.stages.size())
{
const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex];
if (m_context.currentActionIndex >= 0 &&
m_context.currentActionIndex < stage.actions.size())
{
const TestAction &action = stage.actions[m_context.currentActionIndex];
onActionFailed(action.actionId, "執行超時");
return;
}
}
}
// 如果無法確定當前動作,直接移動到下一個
moveToNextAction();
}
// =============================================================================
// 結果處理
// =============================================================================
void ProcedureEngine::processActionResults(const QString &actionId, const QVariantMap &results)
{
// 獲取當前動作定義
const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex];
if (step.type != ActivityType::TEST_TASK_GROUP)
{
return;
}
if (!m_config.testTaskGroups.contains(step.ref))
{
return;
}
const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref];
if (m_context.currentStageIndex < 0 ||
m_context.currentStageIndex >= taskGroup.stages.size())
{
return;
}
const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex];
if (m_context.currentActionIndex < 0 ||
m_context.currentActionIndex >= stage.actions.size())
{
return;
}
const TestAction &action = stage.actions[m_context.currentActionIndex];
// 根據輸出映射寫入表格
for (auto it = action.outputs.begin(); it != action.outputs.end(); ++it)
{
const QString &outputKey = it.key();
const FieldSelector &selector = it.value();
if (results.contains(outputKey))
{
QVariant value = results[outputKey];
setTableCellValue(selector.tableRef, selector.row, selector.column, value);
}
}
}
void ProcedureEngine::displayResult(const QString &displayRef)
{
if (!m_config.resultDisplays.contains(displayRef))
{
emit errorOccurred(QString("找不到結果顯示: %1").arg(displayRef));
return;
}
const ResultDisplay &display = m_config.resultDisplays[displayRef];
qDebug() << "顯示結果:" << display.name;
emit resultDisplayRequested(displayRef, display);
}
void ProcedureEngine::completeProcedure()
{
qDebug() << "程序執行完成";
setStatus(ProcedureStatus::Completed);
emit procedureCompleted();
}
// =============================================================================
// 表格數據管理
// =============================================================================
void ProcedureEngine::initializeTable(const QString &tableRef)
{
if (!m_config.tables.contains(tableRef))
{
qWarning() << "找不到表格定義:" << tableRef;
return;
}
const TableDefinition &tableDef = m_config.tables[tableRef];
// 初始化表格數據
QVector<QVector<QVariant>> data;
int rowCount = tableDef.rowCount > 0 ? tableDef.rowCount : 10;
int colCount = tableDef.fields.size() > 0 ? tableDef.fields.size() : tableDef.columnCount;
for (int row = 0; row < rowCount; row++)
{
QVector<QVariant> rowData;
for (int col = 0; col < colCount; col++)
{
if (col < tableDef.fields.size())
{
rowData.append(tableDef.fields[col].defaultValue);
}
else
{
rowData.append(QVariant());
}
}
data.append(rowData);
}
// 應用靜態單元格
for (const StaticCell &cell : tableDef.staticCells)
{
if (cell.row < data.size() && cell.column < data[cell.row].size())
{
data[cell.row][cell.column] = cell.value;
}
}
m_tableData[tableRef] = data;
emit tableInitialized(tableRef, tableDef);
}
QVariant ProcedureEngine::getTableCellValue(const QString &tableRef, int row, int column) const
{
if (!m_tableData.contains(tableRef))
{
return QVariant();
}
const auto &data = m_tableData[tableRef];
if (row < 0 || row >= data.size())
{
return QVariant();
}
if (column < 0 || column >= data[row].size())
{
return QVariant();
}
return data[row][column];
}
void ProcedureEngine::setTableCellValue(const QString &tableRef, int row, int column, const QVariant &value)
{
if (!m_tableData.contains(tableRef))
{
return;
}
auto &data = m_tableData[tableRef];
if (row < 0 || row >= data.size())
{
return;
}
// 自動擴展列
while (column >= data[row].size())
{
data[row].append(QVariant());
}
data[row][column] = value;
emit tableDataChanged(tableRef, row, column, value);
}
QVector<QVector<QVariant>> ProcedureEngine::getTableData(const QString &tableRef) const
{
if (m_tableData.contains(tableRef))
{
return m_tableData[tableRef];
}
return QVector<QVector<QVariant>>();
}
// =============================================================================
// 條件評估
// =============================================================================
bool ProcedureEngine::evaluateCondition(const QString &condition)
{
// 簡單的條件評估
// TODO: 實現完整的表達式解析器
if (condition.isEmpty() || condition == "true")
{
return true;
}
if (condition == "false")
{
return false;
}
// 支持簡單的表格引用條件
// 格式: table[row][col] == value
static QRegularExpression tableRefRe(R"((\w+)\[(\d+)\]\[(\d+)\]\s*(==|!=|>|<|>=|<=)\s*(.+))");
QRegularExpressionMatch match = tableRefRe.match(condition);
if (match.hasMatch())
{
QString tableRef = match.captured(1);
int row = match.captured(2).toInt();
int col = match.captured(3).toInt();
QString op = match.captured(4);
QString valueStr = match.captured(5).trimmed();
QVariant cellValue = getTableCellValue(tableRef, row, col);
QVariant compareValue = valueStr;
// 簡單比較
if (op == "==")
{
return cellValue == compareValue;
}
else if (op == "!=")
{
return cellValue != compareValue;
}
else if (op == ">")
{
return cellValue.toDouble() > compareValue.toDouble();
}
else if (op == "<")
{
return cellValue.toDouble() < compareValue.toDouble();
}
else if (op == ">=")
{
return cellValue.toDouble() >= compareValue.toDouble();
}
else if (op == "<=")
{
return cellValue.toDouble() <= compareValue.toDouble();
}
}
qWarning() << "無法評估條件:" << condition;
return false;
}
// =============================================================================
// 狀態查詢
// =============================================================================
void ProcedureEngine::setStatus(ProcedureStatus status)
{
if (m_status != status)
{
m_status = status;
emit statusChanged(status);
}
}
ProcedureStatus ProcedureEngine::status() const
{
return m_status;
}
ProcedureConfig ProcedureEngine::config() const
{
return m_config;
}
ExecutionContext ProcedureEngine::executionContext() const
{
return m_context;
}
ActivityStep ProcedureEngine::getCurrentActivity() const
{
if (m_context.currentActivityIndex >= 0 &&
m_context.currentActivityIndex < m_config.activitySequence.size())
{
return m_config.activitySequence[m_context.currentActivityIndex];
}
return ActivityStep();
}
TestTaskGroup ProcedureEngine::getCurrentTaskGroup() const
{
ActivityStep step = getCurrentActivity();
if (step.type == ActivityType::TEST_TASK_GROUP &&
m_config.testTaskGroups.contains(step.ref))
{
return m_config.testTaskGroups[step.ref];
}
return TestTaskGroup();
}
TestActivityGroup ProcedureEngine::getCurrentStage() const
{
TestTaskGroup taskGroup = getCurrentTaskGroup();
if (m_context.currentStageIndex >= 0 &&
m_context.currentStageIndex < taskGroup.stages.size())
{
return taskGroup.stages[m_context.currentStageIndex];
}
return TestActivityGroup();
}
TestAction ProcedureEngine::getCurrentAction() const
{
TestActivityGroup stage = getCurrentStage();
if (m_context.currentActionIndex >= 0 &&
m_context.currentActionIndex < stage.actions.size())
{
return stage.actions[m_context.currentActionIndex];
}
return TestAction();
}
int ProcedureEngine::getActivityCount() const
{
return m_config.activitySequence.size();
}
int ProcedureEngine::getCurrentActivityIndex() const
{
return m_context.currentActivityIndex;
}
double ProcedureEngine::getProgress() const
{
if (m_config.activitySequence.isEmpty())
{
return 0.0;
}
// 基於活動數量計算簡單進度
double activityProgress = static_cast<double>(m_context.currentActivityIndex) / m_config.activitySequence.size();
// 可以進一步細化到階段和動作級別
// TODO: 更精確的進度計算
return qBound(0.0, activityProgress * 100.0, 100.0);
}