| @@ -17,13 +17,13 @@ bool validateConfig(const ContactNodeConfig &config, std::string *error) | |||||
| { | { | ||||
| if (!config.address.isValid() || config.address.area() != RegisterArea::M) | if (!config.address.isValid() || config.address.area() != RegisterArea::M) | ||||
| { | { | ||||
| setError(error, "contact node requires a valid M address"); | |||||
| setError(error, "触点节点必须使用有效的 M 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (config.mode != ContactMode::NormallyOpen | if (config.mode != ContactMode::NormallyOpen | ||||
| && config.mode != ContactMode::NormallyClosed) | && config.mode != ContactMode::NormallyClosed) | ||||
| { | { | ||||
| setError(error, "contact node has an unsupported mode"); | |||||
| setError(error, "触点节点使用了不支持的模式"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -33,14 +33,14 @@ bool validateConfig(const CoilNodeConfig &config, std::string *error) | |||||
| { | { | ||||
| if (!config.address.isValid() || config.address.area() != RegisterArea::M) | if (!config.address.isValid() || config.address.area() != RegisterArea::M) | ||||
| { | { | ||||
| setError(error, "coil node requires a valid M address"); | |||||
| setError(error, "线圈节点必须使用有效的 M 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (config.mode != CoilMode::Normal | if (config.mode != CoilMode::Normal | ||||
| && config.mode != CoilMode::Set | && config.mode != CoilMode::Set | ||||
| && config.mode != CoilMode::Reset) | && config.mode != CoilMode::Reset) | ||||
| { | { | ||||
| setError(error, "coil node has an unsupported mode"); | |||||
| setError(error, "线圈节点使用了不支持的模式"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -50,7 +50,7 @@ bool validateConfig(const CompareNodeConfig &config, std::string *error) | |||||
| { | { | ||||
| if (!config.address.isValid() || config.address.area() != RegisterArea::D) | if (!config.address.isValid() || config.address.area() != RegisterArea::D) | ||||
| { | { | ||||
| setError(error, "comparison node requires a valid D address"); | |||||
| setError(error, "比较节点必须使用有效的 D 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (config.comparison != ComparisonOperator::Equal | if (config.comparison != ComparisonOperator::Equal | ||||
| @@ -60,7 +60,7 @@ bool validateConfig(const CompareNodeConfig &config, std::string *error) | |||||
| && config.comparison != ComparisonOperator::GreaterThan | && config.comparison != ComparisonOperator::GreaterThan | ||||
| && config.comparison != ComparisonOperator::GreaterThanOrEqual) | && config.comparison != ComparisonOperator::GreaterThanOrEqual) | ||||
| { | { | ||||
| setError(error, "comparison node has an unsupported operator"); | |||||
| setError(error, "比较节点使用了不支持的运算符"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -93,7 +93,7 @@ bool validateUniqueExpressionIds( | |||||
| std::sort(ids.begin(), ids.end()); | std::sort(ids.begin(), ids.end()); | ||||
| if (std::adjacent_find(ids.cbegin(), ids.cend()) != ids.cend()) | if (std::adjacent_find(ids.cbegin(), ids.cend()) != ids.cend()) | ||||
| { | { | ||||
| setError(error, "condition expression ids must be unique within a rung"); | |||||
| setError(error, "同一网络内的条件表达式 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -138,7 +138,7 @@ bool LogicNode::validate(std::string *error) const | |||||
| { | { | ||||
| if (id.empty()) | if (id.empty()) | ||||
| { | { | ||||
| setError(error, "logic node id must not be empty"); | |||||
| setError(error, "逻辑节点 ID 不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return std::visit( | return std::visit( | ||||
| @@ -174,28 +174,28 @@ bool ConditionExpression::validate(std::string *error) const | |||||
| { | { | ||||
| if (id.empty()) | if (id.empty()) | ||||
| { | { | ||||
| setError(error, "condition expression id must not be empty"); | |||||
| setError(error, "条件表达式 ID 不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (kind == ConditionExpressionKind::Node) | if (kind == ConditionExpressionKind::Node) | ||||
| { | { | ||||
| if (!node.has_value() || !children.empty() || !node->isCondition()) | if (!node.has_value() || !children.empty() || !node->isCondition()) | ||||
| { | { | ||||
| setError(error, "condition leaf requires one condition node and no children"); | |||||
| setError(error, "条件叶节点必须包含一个条件节点且不能包含子表达式"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return node->validate(error); | return node->validate(error); | ||||
| } | } | ||||
| if (node.has_value() || children.size() < 2U) | if (node.has_value() || children.size() < 2U) | ||||
| { | { | ||||
| setError(error, "series and parallel expressions require at least two children"); | |||||
| setError(error, "串联和并联表达式至少需要两个子表达式"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| for (const ConditionExpression &child : children) | for (const ConditionExpression &child : children) | ||||
| { | { | ||||
| if (child.kind == kind) | if (child.kind == kind) | ||||
| { | { | ||||
| setError(error, "nested expressions of the same kind must be normalized"); | |||||
| setError(error, "同类型嵌套表达式必须先完成归一化"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (!child.validate(error)) | if (!child.validate(error)) | ||||
| @@ -216,7 +216,7 @@ bool ConditionExpression::validateForRunning(std::string *error) const | |||||
| { | { | ||||
| if (!node->isConfigured()) | if (!node->isConfigured()) | ||||
| { | { | ||||
| setError(error, "ladder condition " + node->id + " is not configured"); | |||||
| setError(error, "梯形图条件节点 " + node->id + " 尚未配置"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -343,7 +343,7 @@ bool LadderRung::validateForRunning(std::string *error) const | |||||
| } | } | ||||
| if (!condition.has_value() || !output.has_value()) | if (!condition.has_value() || !output.has_value()) | ||||
| { | { | ||||
| setError(error, "incomplete ladder network requires conditions and an output coil"); | |||||
| setError(error, "未完成的梯形图网络必须同时包含条件和输出线圈"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (!condition->validateForRunning(error)) | if (!condition->validateForRunning(error)) | ||||
| @@ -352,7 +352,7 @@ bool LadderRung::validateForRunning(std::string *error) const | |||||
| } | } | ||||
| if (!output->isConfigured()) | if (!output->isConfigured()) | ||||
| { | { | ||||
| setError(error, "output coil " + output->id + " is not configured"); | |||||
| setError(error, "输出线圈 " + output->id + " 尚未配置"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -362,7 +362,7 @@ bool LadderRung::validateStructure(std::string *error) const | |||||
| { | { | ||||
| if (id.empty() || name.empty()) | if (id.empty() || name.empty()) | ||||
| { | { | ||||
| setError(error, "ladder rung id and name must not be empty"); | |||||
| setError(error, "梯形图网络 ID 和名称不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| std::vector<std::string> node_ids; | std::vector<std::string> node_ids; | ||||
| @@ -383,7 +383,7 @@ bool LadderRung::validateStructure(std::string *error) const | |||||
| { | { | ||||
| if (!output->validate(error) || !output->isOutput()) | if (!output->validate(error) || !output->isOutput()) | ||||
| { | { | ||||
| setError(error, "ladder rung output must be a coil node"); | |||||
| setError(error, "梯形图网络输出必须是线圈节点"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| node_ids.push_back(output->id); | node_ids.push_back(output->id); | ||||
| @@ -391,7 +391,7 @@ bool LadderRung::validateStructure(std::string *error) const | |||||
| std::sort(node_ids.begin(), node_ids.end()); | std::sort(node_ids.begin(), node_ids.end()); | ||||
| if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend()) | if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend()) | ||||
| { | { | ||||
| setError(error, "logic node ids must be unique within a rung"); | |||||
| setError(error, "同一网络内的逻辑节点 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -417,12 +417,12 @@ bool ControlLogic::validateStructure(std::string *error) const | |||||
| { | { | ||||
| if (id.empty() || name.empty()) | if (id.empty() || name.empty()) | ||||
| { | { | ||||
| setError(error, "control logic id and name must not be empty"); | |||||
| setError(error, "控制逻辑 ID 和名称不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (hasDuplicateId(rungs)) | if (hasDuplicateId(rungs)) | ||||
| { | { | ||||
| setError(error, "ladder rung ids must be unique within a logic"); | |||||
| setError(error, "同一控制逻辑内的网络 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| std::vector<std::string> node_ids; | std::vector<std::string> node_ids; | ||||
| @@ -452,13 +452,13 @@ bool ControlLogic::validateStructure(std::string *error) const | |||||
| std::sort(expression_ids.begin(), expression_ids.end()); | std::sort(expression_ids.begin(), expression_ids.end()); | ||||
| if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend()) | if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend()) | ||||
| { | { | ||||
| setError(error, "logic node ids must be unique within a logic"); | |||||
| setError(error, "同一控制逻辑内的逻辑节点 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (std::adjacent_find(expression_ids.cbegin(), expression_ids.cend()) | if (std::adjacent_find(expression_ids.cbegin(), expression_ids.cend()) | ||||
| != expression_ids.cend()) | != expression_ids.cend()) | ||||
| { | { | ||||
| setError(error, "condition expression ids must be unique within a logic"); | |||||
| setError(error, "同一控制逻辑内的条件表达式 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -31,19 +31,19 @@ bool HmiControl::validate(std::string *error) const | |||||
| { | { | ||||
| if (id.empty()) | if (id.empty()) | ||||
| { | { | ||||
| setError(error, "HMI control id must not be empty"); | |||||
| setError(error, "HMI 控件 ID 不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (bounds.width <= 0 || bounds.height <= 0) | if (bounds.width <= 0 || bounds.height <= 0) | ||||
| { | { | ||||
| setError(error, "HMI control bounds must have positive size"); | |||||
| setError(error, "HMI 控件的宽度和高度必须大于 0"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| for (const auto &property : properties) | for (const auto &property : properties) | ||||
| { | { | ||||
| if (property.first.empty()) | if (property.first.empty()) | ||||
| { | { | ||||
| setError(error, "HMI control property names must not be empty"); | |||||
| setError(error, "HMI 控件属性名称不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| @@ -51,7 +51,7 @@ bool HmiControl::validate(std::string *error) const | |||||
| { | { | ||||
| if (binding.has_value() && binding->area() != RegisterArea::M) | if (binding.has_value() && binding->area() != RegisterArea::M) | ||||
| { | { | ||||
| setError(error, "button and indicator controls require an M address"); | |||||
| setError(error, "按钮和指示灯必须绑定 M 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| @@ -59,13 +59,13 @@ bool HmiControl::validate(std::string *error) const | |||||
| { | { | ||||
| if (binding.has_value() && binding->area() != RegisterArea::D) | if (binding.has_value() && binding->area() != RegisterArea::D) | ||||
| { | { | ||||
| setError(error, "numeric controls require a D address"); | |||||
| setError(error, "数值控件必须绑定 D 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| if (binding.has_value() && !binding->isValid()) | if (binding.has_value() && !binding->isValid()) | ||||
| { | { | ||||
| setError(error, "HMI control binding has an invalid address"); | |||||
| setError(error, "HMI 控件绑定了无效地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -92,12 +92,12 @@ bool HmiPage::validate(std::string *error) const | |||||
| { | { | ||||
| if (id.empty() || name.empty()) | if (id.empty() || name.empty()) | ||||
| { | { | ||||
| setError(error, "HMI page id and name must not be empty"); | |||||
| setError(error, "HMI 页面 ID 和名称不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (width <= 0 || height <= 0) | if (width <= 0 || height <= 0) | ||||
| { | { | ||||
| setError(error, "HMI page size must be positive"); | |||||
| setError(error, "HMI 页面尺寸必须大于 0"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -113,13 +113,13 @@ bool HmiPage::validate(std::string *error) const | |||||
| || control.bounds.x > width - control.bounds.width | || control.bounds.x > width - control.bounds.width | ||||
| || control.bounds.y > height - control.bounds.height) | || control.bounds.y > height - control.bounds.height) | ||||
| { | { | ||||
| setError(error, "HMI control bounds must stay within the page"); | |||||
| setError(error, "HMI 控件不能超出页面范围"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| // 检查控件 id 是否唯一 | // 检查控件 id 是否唯一 | ||||
| if (std::find(ids.cbegin(), ids.cend(), control.id) != ids.cend()) | if (std::find(ids.cbegin(), ids.cend(), control.id) != ids.cend()) | ||||
| { | { | ||||
| setError(error, "HMI control ids must be unique within a page"); | |||||
| setError(error, "同一 HMI 页面内的控件 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| ids.push_back(control.id); | ids.push_back(control.id); | ||||
| @@ -137,7 +137,7 @@ bool HmiPage::validateForRunning(std::string *error) const | |||||
| { | { | ||||
| if (!control.isConfigured()) | if (!control.isConfigured()) | ||||
| { | { | ||||
| setError(error, "HMI control " + control.id + " is not bound to a register"); | |||||
| setError(error, "HMI 控件 " + control.id + " 尚未绑定寄存器"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| @@ -39,17 +39,17 @@ bool Project::validate(std::string *error) const | |||||
| { | { | ||||
| if (metadata.id.empty() || metadata.name.empty() || metadata.formatVersion.empty()) | if (metadata.id.empty() || metadata.name.empty() || metadata.formatVersion.empty()) | ||||
| { | { | ||||
| setError(error, "project id, name and format version must not be empty"); | |||||
| setError(error, "工程 ID、名称和格式版本不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (containsDuplicateId(hmiPages)) | if (containsDuplicateId(hmiPages)) | ||||
| { | { | ||||
| setError(error, "HMI page ids must be unique within a project"); | |||||
| setError(error, "工程内的 HMI 页面 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (containsDuplicateId(controlLogics)) | if (containsDuplicateId(controlLogics)) | ||||
| { | { | ||||
| setError(error, "control logic ids must be unique within a project"); | |||||
| setError(error, "工程内的控制逻辑 ID 必须唯一"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| for (const HmiPage &page : hmiPages) | for (const HmiPage &page : hmiPages) | ||||
| @@ -67,7 +67,7 @@ bool readValue( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::MissingField, | ProjectStorageError::MissingField, | ||||
| "missing required field " + fieldPath(context, field)); | |||||
| "缺少必填字段:" + fieldPath(context, field)); | |||||
| } | } | ||||
| *value = object.value(key); | *value = object.value(key); | ||||
| return true; | return true; | ||||
| @@ -90,7 +90,7 @@ bool readString( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " must be a string"); | |||||
| fieldPath(context, field) + " 必须是字符串"); | |||||
| } | } | ||||
| *value = toUtf8(json_value.toString()); | *value = toUtf8(json_value.toString()); | ||||
| return true; | return true; | ||||
| @@ -113,7 +113,7 @@ bool readBool( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " must be a boolean"); | |||||
| fieldPath(context, field) + " 必须是布尔值"); | |||||
| } | } | ||||
| *value = json_value.toBool(); | *value = json_value.toBool(); | ||||
| return true; | return true; | ||||
| @@ -138,7 +138,7 @@ bool readInt( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " must be an integer"); | |||||
| fieldPath(context, field) + " 必须是整数"); | |||||
| } | } | ||||
| // Qt JSON 统一用 double 表示数值,需要额外确认它能无损转换为 int | // Qt JSON 统一用 double 表示数值,需要额外确认它能无损转换为 int | ||||
| @@ -148,7 +148,7 @@ bool readInt( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " is outside the supported integer range"); | |||||
| fieldPath(context, field) + " 超出支持的整数范围"); | |||||
| } | } | ||||
| *value = static_cast<int>(number); | *value = static_cast<int>(number); | ||||
| return true; | return true; | ||||
| @@ -171,7 +171,7 @@ bool readObject( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " must be an object"); | |||||
| fieldPath(context, field) + " 必须是对象"); | |||||
| } | } | ||||
| *value = json_value.toObject(); | *value = json_value.toObject(); | ||||
| return true; | return true; | ||||
| @@ -194,7 +194,7 @@ bool readArray( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| fieldPath(context, field) + " must be an array"); | |||||
| fieldPath(context, field) + " 必须是数组"); | |||||
| } | } | ||||
| *value = json_value.toArray(); | *value = json_value.toArray(); | ||||
| return true; | return true; | ||||
| @@ -246,7 +246,7 @@ bool parseAddress( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".area must be M or D"); | |||||
| context + ".area 必须是 M 或 D"); | |||||
| } | } | ||||
| *address = RegisterAddress{area, index}; | *address = RegisterAddress{area, index}; | ||||
| @@ -313,7 +313,7 @@ bool parseHmiControlType( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "unsupported HMI control type " + value); | |||||
| "不支持的 HMI 控件类型:" + value); | |||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -393,7 +393,7 @@ bool parseProperties( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "HMI control property values must be strings"); | |||||
| "HMI 控件属性值必须是字符串"); | |||||
| } | } | ||||
| properties->emplace(toUtf8(current.key()), toUtf8(current.value().toString())); | properties->emplace(toUtf8(current.key()), toUtf8(current.value().toString())); | ||||
| } | } | ||||
| @@ -458,7 +458,7 @@ bool parseHmiControl( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".binding must be an object or null"); | |||||
| context + ".binding 必须是对象或 null"); | |||||
| } | } | ||||
| RegisterAddress address{RegisterArea::M, 0}; | RegisterAddress address{RegisterArea::M, 0}; | ||||
| @@ -515,7 +515,7 @@ bool parseHmiPage( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".controls items must be objects"); | |||||
| context + ".controls 的元素必须是对象"); | |||||
| } | } | ||||
| HmiControl control; | HmiControl control; | ||||
| if (!parseHmiControl( | if (!parseHmiControl( | ||||
| @@ -555,7 +555,7 @@ bool parseContactMode( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "unsupported contact mode " + value); | |||||
| "不支持的触点模式:" + value); | |||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -603,7 +603,7 @@ bool parseCoilMode(const std::string &value, CoilMode *mode, ParseState *state) | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "unsupported coil mode " + value); | |||||
| "不支持的线圈模式:" + value); | |||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -678,7 +678,7 @@ bool parseComparison( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "unsupported comparison operator " + value); | |||||
| "不支持的比较运算符:" + value); | |||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -804,7 +804,7 @@ bool parseNodeConfig( | |||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "unsupported logic node type " + type); | |||||
| "不支持的逻辑节点类型:" + type); | |||||
| } | } | ||||
| // 解析逻辑节点标识及其多态配置 | // 解析逻辑节点标识及其多态配置 | ||||
| @@ -892,7 +892,7 @@ bool parseConditionExpression( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".kind must be node, series or parallel"); | |||||
| context + ".kind 必须是 node、series 或 parallel"); | |||||
| } | } | ||||
| QJsonArray children; | QJsonArray children; | ||||
| if (!readArray(object, "children", context, &children, state)) | if (!readArray(object, "children", context, &children, state)) | ||||
| @@ -908,7 +908,7 @@ bool parseConditionExpression( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".children items must be objects"); | |||||
| context + ".children 的元素必须是对象"); | |||||
| } | } | ||||
| ConditionExpression child; | ConditionExpression child; | ||||
| if (!parseConditionExpression( | if (!parseConditionExpression( | ||||
| @@ -967,7 +967,7 @@ bool parseLadderRung( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".condition must be an object or null"); | |||||
| context + ".condition 必须是对象或 null"); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -988,7 +988,7 @@ bool parseLadderRung( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".output must be an object or null"); | |||||
| context + ".output 必须是对象或 null"); | |||||
| } | } | ||||
| LogicNode node; | LogicNode node; | ||||
| if (!parseLogicNode(output.toObject(), context + ".output", &node, state)) | if (!parseLogicNode(output.toObject(), context + ".output", &node, state)) | ||||
| @@ -1035,7 +1035,7 @@ bool parseControlLogic( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| context + ".rungs items must be objects"); | |||||
| context + ".rungs 的元素必须是对象"); | |||||
| } | } | ||||
| LadderRung rung; | LadderRung rung; | ||||
| if (!parseLadderRung( | if (!parseLadderRung( | ||||
| @@ -1095,7 +1095,7 @@ bool parseProject( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::UnsupportedVersion, | ProjectStorageError::UnsupportedVersion, | ||||
| "unsupported project format version " + project->metadata.formatVersion); | |||||
| "不支持的工程格式版本:" + project->metadata.formatVersion); | |||||
| } | } | ||||
| if (!readString(object, "id", "project", &project->metadata.id, state) | if (!readString(object, "id", "project", &project->metadata.id, state) | ||||
| @@ -1114,7 +1114,7 @@ bool parseProject( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "project.hmiPages items must be objects"); | |||||
| "project.hmiPages 的元素必须是对象"); | |||||
| } | } | ||||
| HmiPage page; | HmiPage page; | ||||
| if (!parseHmiPage( | if (!parseHmiPage( | ||||
| @@ -1135,7 +1135,7 @@ bool parseProject( | |||||
| { | { | ||||
| return state->fail( | return state->fail( | ||||
| ProjectStorageError::InvalidField, | ProjectStorageError::InvalidField, | ||||
| "project.controlLogics items must be objects"); | |||||
| "project.controlLogics 的元素必须是对象"); | |||||
| } | } | ||||
| ControlLogic logic; | ControlLogic logic; | ||||
| if (!parseControlLogic( | if (!parseControlLogic( | ||||
| @@ -1174,7 +1174,7 @@ ProjectSaveResult JsonProjectStorage::save( | |||||
| { | { | ||||
| return {false, | return {false, | ||||
| ProjectStorageError::UnsupportedVersion, | ProjectStorageError::UnsupportedVersion, | ||||
| "unsupported project format version " + project.metadata.formatVersion}; | |||||
| "不支持的工程格式版本:" + project.metadata.formatVersion}; | |||||
| } | } | ||||
| // QSaveFile 先写临时文件,仅在 commit 成功后替换目标文件 | // QSaveFile 先写临时文件,仅在 commit 成功后替换目标文件 | ||||
| @@ -1226,7 +1226,7 @@ ProjectLoadResult JsonProjectStorage::load(const std::string &file_path) | |||||
| if (parse_error.error != QJsonParseError::NoError || !document.isObject()) | if (parse_error.error != QJsonParseError::NoError || !document.isObject()) | ||||
| { | { | ||||
| const QString message = parse_error.error == QJsonParseError::NoError | const QString message = parse_error.error == QJsonParseError::NoError | ||||
| ? QStringLiteral("project JSON root must be an object") | |||||
| ? QStringLiteral("工程 JSON 根节点必须是对象") | |||||
| : parse_error.errorString(); | : parse_error.errorString(); | ||||
| return {false, | return {false, | ||||
| {}, | {}, | ||||
| @@ -147,7 +147,7 @@ HmiEditorResult HmiEditorService::addControl( | |||||
| const HmiPage *page = findPage(page_id); | const HmiPage *page = findPage(page_id); | ||||
| if (page == nullptr) | if (page == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::PageNotFound, "HMI page was not found"); | |||||
| return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面"); | |||||
| } | } | ||||
| // 新控件初始不绑定寄存器,避免自动分配地址造成误写风险 | // 新控件初始不绑定寄存器,避免自动分配地址造成误写风险 | ||||
| @@ -172,11 +172,11 @@ HmiEditorResult HmiEditorService::removeControl( | |||||
| { | { | ||||
| if (findPage(page_id) == nullptr) | if (findPage(page_id) == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::PageNotFound, "HMI page was not found"); | |||||
| return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面"); | |||||
| } | } | ||||
| if (findControl(page_id, control_id) == nullptr) | if (findControl(page_id, control_id) == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::ControlNotFound, "HMI control was not found"); | |||||
| return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件"); | |||||
| } | } | ||||
| Project &project = project_service_.editProject(); | Project &project = project_service_.editProject(); | ||||
| @@ -209,11 +209,11 @@ HmiEditorResult HmiEditorService::moveControl( | |||||
| const HmiControl *control = findControl(page_id, control_id); | const HmiControl *control = findControl(page_id, control_id); | ||||
| if (page == nullptr) | if (page == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::PageNotFound, "HMI page was not found"); | |||||
| return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面"); | |||||
| } | } | ||||
| if (control == nullptr) | if (control == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::ControlNotFound, "HMI control was not found"); | |||||
| return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件"); | |||||
| } | } | ||||
| // 先校验候选位置,失败时不修改工程模型 | // 先校验候选位置,失败时不修改工程模型 | ||||
| @@ -247,15 +247,15 @@ HmiEditorResult HmiEditorService::updateControl( | |||||
| const HmiControl *existing = findControl(page_id, control_id); | const HmiControl *existing = findControl(page_id, control_id); | ||||
| if (page == nullptr) | if (page == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::PageNotFound, "HMI page was not found"); | |||||
| return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面"); | |||||
| } | } | ||||
| if (existing == nullptr) | if (existing == nullptr) | ||||
| { | { | ||||
| return failure(HmiEditorError::ControlNotFound, "HMI control was not found"); | |||||
| return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件"); | |||||
| } | } | ||||
| if (control.type != existing->type) | if (control.type != existing->type) | ||||
| { | { | ||||
| return failure(HmiEditorError::InvalidControl, "HMI control type cannot be changed"); | |||||
| return failure(HmiEditorError::InvalidControl, "不能修改已创建 HMI 控件的类型"); | |||||
| } | } | ||||
| std::string error; | std::string error; | ||||
| @@ -265,7 +265,7 @@ HmiEditorResult HmiEditorService::updateControl( | |||||
| } | } | ||||
| if (hasDuplicateControlId(*page, control_id, control.id)) | if (hasDuplicateControlId(*page, control_id, control.id)) | ||||
| { | { | ||||
| return failure(HmiEditorError::DuplicateId, "HMI control id must be unique within a page"); | |||||
| return failure(HmiEditorError::DuplicateId, "同一 HMI 页面内的控件 ID 必须唯一"); | |||||
| } | } | ||||
| Project &project = project_service_.editProject(); | Project &project = project_service_.editProject(); | ||||
| @@ -284,7 +284,7 @@ bool HmiEditorService::validateEditableControl( | |||||
| { | { | ||||
| if (control.id.empty()) | if (control.id.empty()) | ||||
| { | { | ||||
| setError(error, "HMI control id must not be empty"); | |||||
| setError(error, "HMI 控件 ID 不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (control.bounds.width <= 0 || control.bounds.height <= 0 | if (control.bounds.width <= 0 || control.bounds.height <= 0 | ||||
| @@ -293,20 +293,20 @@ bool HmiEditorService::validateEditableControl( | |||||
| || control.bounds.x > page.width - control.bounds.width | || control.bounds.x > page.width - control.bounds.width | ||||
| || control.bounds.y > page.height - control.bounds.height) | || control.bounds.y > page.height - control.bounds.height) | ||||
| { | { | ||||
| setError(error, "HMI control bounds must stay within the page"); | |||||
| setError(error, "HMI 控件不能超出页面范围"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| for (const auto &property : control.properties) | for (const auto &property : control.properties) | ||||
| { | { | ||||
| if (property.first.empty()) | if (property.first.empty()) | ||||
| { | { | ||||
| setError(error, "HMI control property names must not be empty"); | |||||
| setError(error, "HMI 控件属性名称不能为空"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| if (control.binding.has_value() && !control.binding->isValid()) | if (control.binding.has_value() && !control.binding->isValid()) | ||||
| { | { | ||||
| setError(error, "HMI control binding has an invalid address"); | |||||
| setError(error, "HMI 控件绑定了无效地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (control.binding.has_value() | if (control.binding.has_value() | ||||
| @@ -314,7 +314,7 @@ bool HmiEditorService::validateEditableControl( | |||||
| || control.type == HmiControlType::Indicator) | || control.type == HmiControlType::Indicator) | ||||
| && control.binding->area() != RegisterArea::M) | && control.binding->area() != RegisterArea::M) | ||||
| { | { | ||||
| setError(error, "button and indicator controls require an M address"); | |||||
| setError(error, "按钮和指示灯必须绑定 M 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (control.binding.has_value() | if (control.binding.has_value() | ||||
| @@ -322,7 +322,7 @@ bool HmiEditorService::validateEditableControl( | |||||
| || control.type == HmiControlType::NumericInput) | || control.type == HmiControlType::NumericInput) | ||||
| && control.binding->area() != RegisterArea::D) | && control.binding->area() != RegisterArea::D) | ||||
| { | { | ||||
| setError(error, "numeric controls require a D address"); | |||||
| setError(error, "数值控件必须绑定 D 区地址"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| @@ -346,7 +346,7 @@ LogicEditorResult LogicEditorService::addRung(const std::string &logic_id) | |||||
| const ControlLogic *logic = findLogic(logic_id); | const ControlLogic *logic = findLogic(logic_id); | ||||
| if (logic == nullptr) | if (logic == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::LogicNotFound, "control logic was not found"); | |||||
| return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑"); | |||||
| } | } | ||||
| LadderRung rung; | LadderRung rung; | ||||
| rung.id = makeUniqueRungId(*logic); | rung.id = makeUniqueRungId(*logic); | ||||
| @@ -365,15 +365,15 @@ LogicEditorResult LogicEditorService::removeRung( | |||||
| const ControlLogic *logic = findLogic(logic_id); | const ControlLogic *logic = findLogic(logic_id); | ||||
| if (logic == nullptr) | if (logic == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::LogicNotFound, "control logic was not found"); | |||||
| return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑"); | |||||
| } | } | ||||
| if (findRung(logic_id, rung_id) == nullptr) | if (findRung(logic_id, rung_id) == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::RungNotFound, "ladder rung was not found"); | |||||
| return failure(LogicEditorError::RungNotFound, "未找到梯形图网络"); | |||||
| } | } | ||||
| if (logic->rungs.size() == 1U) | if (logic->rungs.size() == 1U) | ||||
| { | { | ||||
| return failure(LogicEditorError::InvalidOperation, "control logic requires one rung"); | |||||
| return failure(LogicEditorError::InvalidOperation, "控制逻辑至少需要保留一个网络"); | |||||
| } | } | ||||
| Project &project = project_service_.editProject(); | Project &project = project_service_.editProject(); | ||||
| auto target = std::find_if( | auto target = std::find_if( | ||||
| @@ -397,11 +397,11 @@ LogicEditorResult LogicEditorService::appendCondition( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| logic == nullptr ? LogicEditorError::LogicNotFound : LogicEditorError::RungNotFound, | logic == nullptr ? LogicEditorError::LogicNotFound : LogicEditorError::RungNotFound, | ||||
| logic == nullptr ? "control logic was not found" : "ladder rung was not found"); | |||||
| logic == nullptr ? "未找到控制逻辑" : "未找到梯形图网络"); | |||||
| } | } | ||||
| if (!isConditionConfig(config)) | if (!isConditionConfig(config)) | ||||
| { | { | ||||
| return failure(LogicEditorError::InvalidNode, "ladder condition cannot be a coil"); | |||||
| return failure(LogicEditorError::InvalidNode, "梯形图条件不能使用线圈节点"); | |||||
| } | } | ||||
| const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | ||||
| ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ||||
| @@ -435,7 +435,7 @@ LogicEditorResult LogicEditorService::insertConditionAfter( | |||||
| const ControlLogic *logic = findLogic(logic_id); | const ControlLogic *logic = findLogic(logic_id); | ||||
| if (logic == nullptr || findRung(logic_id, rung_id) == nullptr) | if (logic == nullptr || findRung(logic_id, rung_id) == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::RungNotFound, "ladder network was not found"); | |||||
| return failure(LogicEditorError::RungNotFound, "未找到梯形图网络"); | |||||
| } | } | ||||
| const LadderRung *existing_rung = findRung(logic_id, rung_id); | const LadderRung *existing_rung = findRung(logic_id, rung_id); | ||||
| if (!isConditionConfig(config) | if (!isConditionConfig(config) | ||||
| @@ -443,7 +443,7 @@ LogicEditorResult LogicEditorService::insertConditionAfter( | |||||
| || !existing_rung->condition.has_value() | || !existing_rung->condition.has_value() | ||||
| || findConditionNode(*existing_rung->condition, target_node_id) == nullptr) | || findConditionNode(*existing_rung->condition, target_node_id) == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::NodeNotFound, "series insertion target was not found"); | |||||
| return failure(LogicEditorError::NodeNotFound, "未找到串联插入目标"); | |||||
| } | } | ||||
| const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | ||||
| ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ||||
| @@ -482,30 +482,30 @@ LogicEditorResult LogicEditorService::addParallelBranch( | |||||
| const ControlLogic *logic = findLogic(logic_id); | const ControlLogic *logic = findLogic(logic_id); | ||||
| if (logic == nullptr || findRung(logic_id, rung_id) == nullptr) | if (logic == nullptr || findRung(logic_id, rung_id) == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::RungNotFound, "ladder network was not found"); | |||||
| return failure(LogicEditorError::RungNotFound, "未找到梯形图网络"); | |||||
| } | } | ||||
| if (!isConditionConfig(config) || selected_node_ids.empty()) | if (!isConditionConfig(config) || selected_node_ids.empty()) | ||||
| { | { | ||||
| return failure(LogicEditorError::InvalidOperation, "parallel branch requires a selection"); | |||||
| return failure(LogicEditorError::InvalidOperation, "建立并联支路前必须选择节点"); | |||||
| } | } | ||||
| const LadderRung *existing_rung = findRung(logic_id, rung_id); | const LadderRung *existing_rung = findRung(logic_id, rung_id); | ||||
| if (!existing_rung->condition.has_value()) | if (!existing_rung->condition.has_value()) | ||||
| { | { | ||||
| return failure(LogicEditorError::InvalidOperation, "ladder network has no condition"); | |||||
| return failure(LogicEditorError::InvalidOperation, "梯形图网络尚无条件节点"); | |||||
| } | } | ||||
| NodeIdSet selected_ids(selected_node_ids.cbegin(), selected_node_ids.cend()); | NodeIdSet selected_ids(selected_node_ids.cbegin(), selected_node_ids.cend()); | ||||
| if (selected_ids.size() != selected_node_ids.size()) | if (selected_ids.size() != selected_node_ids.size()) | ||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicEditorError::InvalidOperation, | LogicEditorError::InvalidOperation, | ||||
| "parallel selection contains duplicates"); | |||||
| "并联选择中存在重复节点"); | |||||
| } | } | ||||
| const NodeIdSet available_ids = conditionNodeIds(*existing_rung->condition); | const NodeIdSet available_ids = conditionNodeIds(*existing_rung->condition); | ||||
| if (!isSubset(selected_ids, available_ids)) | if (!isSubset(selected_ids, available_ids)) | ||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicEditorError::NodeNotFound, | LogicEditorError::NodeNotFound, | ||||
| "parallel selection contains an unknown node"); | |||||
| "并联选择中包含未知节点"); | |||||
| } | } | ||||
| const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config)); | ||||
| ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config)); | ||||
| @@ -526,7 +526,7 @@ LogicEditorResult LogicEditorService::addParallelBranch( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicEditorError::InvalidOperation, | LogicEditorError::InvalidOperation, | ||||
| "parallel selection must be one continuous logic range"); | |||||
| "并联选择必须是一个连续的逻辑范围"); | |||||
| } | } | ||||
| return {true, LogicEditorError::None, {}, node_id}; | return {true, LogicEditorError::None, {}, node_id}; | ||||
| } | } | ||||
| @@ -540,7 +540,7 @@ LogicEditorResult LogicEditorService::setOutput( | |||||
| const LadderRung *existing_rung = findRung(logic_id, rung_id); | const LadderRung *existing_rung = findRung(logic_id, rung_id); | ||||
| if (logic == nullptr || existing_rung == nullptr || !isOutputConfig(config)) | if (logic == nullptr || existing_rung == nullptr || !isOutputConfig(config)) | ||||
| { | { | ||||
| return failure(LogicEditorError::InvalidNode, "ladder output requires a valid coil"); | |||||
| return failure(LogicEditorError::InvalidNode, "梯形图输出必须使用有效线圈"); | |||||
| } | } | ||||
| const std::string node_id = existing_rung->output.has_value() | const std::string node_id = existing_rung->output.has_value() | ||||
| ? existing_rung->output->id : makeUniqueNodeId(*logic, nodePrefix(config)); | ? existing_rung->output->id : makeUniqueNodeId(*logic, nodePrefix(config)); | ||||
| @@ -557,13 +557,13 @@ LogicEditorResult LogicEditorService::updateNodeConfig( | |||||
| const LogicNode *node = findNode(logic_id, node_id); | const LogicNode *node = findNode(logic_id, node_id); | ||||
| if (node == nullptr) | if (node == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::NodeNotFound, "logic node was not found"); | |||||
| return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点"); | |||||
| } | } | ||||
| if (node->config.index() != config.index()) | if (node->config.index() != config.index()) | ||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicEditorError::UnsupportedNodeChange, | LogicEditorError::UnsupportedNodeChange, | ||||
| "node category cannot be changed after creation"); | |||||
| "节点创建后不能修改节点类别"); | |||||
| } | } | ||||
| LogicNode candidate{node_id, config, true}; | LogicNode candidate{node_id, config, true}; | ||||
| std::string error; | std::string error; | ||||
| @@ -595,7 +595,7 @@ LogicEditorResult LogicEditorService::updateNodeConfig( | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return failure(LogicEditorError::NodeNotFound, "logic node was not found"); | |||||
| return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点"); | |||||
| } | } | ||||
| LogicEditorResult LogicEditorService::removeNode( | LogicEditorResult LogicEditorService::removeNode( | ||||
| @@ -604,7 +604,7 @@ LogicEditorResult LogicEditorService::removeNode( | |||||
| const std::string rung_id = rungIdForNode(logic_id, node_id); | const std::string rung_id = rungIdForNode(logic_id, node_id); | ||||
| if (rung_id.empty()) | if (rung_id.empty()) | ||||
| { | { | ||||
| return failure(LogicEditorError::NodeNotFound, "logic node was not found"); | |||||
| return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点"); | |||||
| } | } | ||||
| const LadderRung *rung = findRung(logic_id, rung_id); | const LadderRung *rung = findRung(logic_id, rung_id); | ||||
| if (rung->output.has_value() && rung->output->id == node_id) | if (rung->output.has_value() && rung->output->id == node_id) | ||||
| @@ -623,7 +623,7 @@ LogicEditorResult LogicEditorService::removeExpression( | |||||
| { | { | ||||
| if (findExpression(logic_id, rung_id, expression_id) == nullptr) | if (findExpression(logic_id, rung_id, expression_id) == nullptr) | ||||
| { | { | ||||
| return failure(LogicEditorError::ExpressionNotFound, "condition branch was not found"); | |||||
| return failure(LogicEditorError::ExpressionNotFound, "未找到条件支路"); | |||||
| } | } | ||||
| Project &project = project_service_.editProject(); | Project &project = project_service_.editProject(); | ||||
| LadderRung *rung = findEditableRung(project, logic_id, rung_id); | LadderRung *rung = findEditableRung(project, logic_id, rung_id); | ||||
| @@ -61,7 +61,7 @@ LogicScanResult OfflineSimulationService::executeOnce() | |||||
| { | { | ||||
| return {false, | return {false, | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "offline simulation is not running", | |||||
| "离线仿真尚未运行", | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| {}}; | {}}; | ||||
| @@ -26,7 +26,7 @@ std::string generateProjectId() | |||||
| ProjectService::ProjectService(ProjectStorage &storage) | ProjectService::ProjectService(ProjectStorage &storage) | ||||
| : storage_(storage), | : storage_(storage), | ||||
| project_(makeNewProject("Untitled")) | |||||
| project_(makeNewProject("未命名工程")) | |||||
| { | { | ||||
| } | } | ||||
| @@ -64,7 +64,7 @@ ProjectOperationResult ProjectService::createNewProject(const std::string &name) | |||||
| return {false, | return {false, | ||||
| ProjectServiceError::InvalidProjectName, | ProjectServiceError::InvalidProjectName, | ||||
| ProjectStorageError::None, | ProjectStorageError::None, | ||||
| "project name must not be empty"}; | |||||
| "工程名称不能为空"}; | |||||
| } | } | ||||
| // 新工程创建成功后清除原文件关联,并标记为待保存 | // 新工程创建成功后清除原文件关联,并标记为待保存 | ||||
| @@ -81,7 +81,7 @@ ProjectOperationResult ProjectService::save() | |||||
| return {false, | return {false, | ||||
| ProjectServiceError::FilePathRequired, | ProjectServiceError::FilePathRequired, | ||||
| ProjectStorageError::None, | ProjectStorageError::None, | ||||
| "project file path is required"}; | |||||
| "必须指定工程文件路径"}; | |||||
| } | } | ||||
| // 复用另存为流程,确保两种保存方式拥有相同的校验和错误处理 | // 复用另存为流程,确保两种保存方式拥有相同的校验和错误处理 | ||||
| return saveAs(current_file_path_); | return saveAs(current_file_path_); | ||||
| @@ -94,7 +94,7 @@ ProjectOperationResult ProjectService::saveAs(const std::string &file_path) | |||||
| return {false, | return {false, | ||||
| ProjectServiceError::FilePathRequired, | ProjectServiceError::FilePathRequired, | ||||
| ProjectStorageError::None, | ProjectStorageError::None, | ||||
| "project file path is required"}; | |||||
| "必须指定工程文件路径"}; | |||||
| } | } | ||||
| std::string validation_error; | std::string validation_error; | ||||
| @@ -126,7 +126,7 @@ ProjectOperationResult ProjectService::load(const std::string &file_path) | |||||
| return {false, | return {false, | ||||
| ProjectServiceError::FilePathRequired, | ProjectServiceError::FilePathRequired, | ||||
| ProjectStorageError::None, | ProjectStorageError::None, | ||||
| "project file path is required"}; | |||||
| "必须指定工程文件路径"}; | |||||
| } | } | ||||
| ProjectLoadResult result = storage_.load(file_path); | ProjectLoadResult result = storage_.load(file_path); | ||||
| @@ -176,7 +176,7 @@ PlcCommunicationResult RuntimeModeService::connectPlc( | |||||
| { | { | ||||
| if (plc_gateway_ == nullptr) | if (plc_gateway_ == nullptr) | ||||
| { | { | ||||
| return {false, "PLC communication is not configured"}; | |||||
| return {false, "PLC 通信服务尚未配置"}; | |||||
| } | } | ||||
| std::vector<RegisterAddress> addresses; | std::vector<RegisterAddress> addresses; | ||||
| const Project &project = project_service_.project(); | const Project &project = project_service_.project(); | ||||
| @@ -96,7 +96,7 @@ LogicScanResult SoftwareLogicExecutor::validate( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "ladder output is not a coil", | |||||
| "梯形图输出不是线圈节点", | |||||
| logic.id, | logic.id, | ||||
| rung.id, | rung.id, | ||||
| rung.output->id); | rung.output->id); | ||||
| @@ -106,7 +106,7 @@ LogicScanResult SoftwareLogicExecutor::validate( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::ConflictingOutput, | LogicScanError::ConflictingOutput, | ||||
| "mixed coil modes target " + output->address.toString(), | |||||
| "同一地址使用了不同线圈模式:" + output->address.toString(), | |||||
| logic.id, | logic.id, | ||||
| rung.id, | rung.id, | ||||
| rung.output->id); | rung.output->id); | ||||
| @@ -180,7 +180,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateExpression( | |||||
| { | { | ||||
| if (value == nullptr) | if (value == nullptr) | ||||
| { | { | ||||
| return failure(LogicScanError::InvalidLogic, "expression result target is missing"); | |||||
| return failure(LogicScanError::InvalidLogic, "缺少表达式结果接收对象"); | |||||
| } | } | ||||
| if (expression.kind == ConditionExpressionKind::Node) | if (expression.kind == ConditionExpressionKind::Node) | ||||
| { | { | ||||
| @@ -222,7 +222,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "condition result target is missing", | |||||
| "缺少条件结果接收对象", | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -239,7 +239,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::RegisterReadFailed, | LogicScanError::RegisterReadFailed, | ||||
| "failed to read " + config.address.toString(), | |||||
| "读取寄存器失败:" + config.address.toString(), | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -255,7 +255,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::RegisterReadFailed, | LogicScanError::RegisterReadFailed, | ||||
| "failed to read " + config.address.toString(), | |||||
| "读取寄存器失败:" + config.address.toString(), | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -267,7 +267,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "condition node contains an output coil", | |||||
| "条件节点不能包含输出线圈", | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -286,7 +286,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "ladder output is not a coil", | |||||
| "梯形图输出不是线圈节点", | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -316,7 +316,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::InvalidLogic, | LogicScanError::InvalidLogic, | ||||
| "unsupported coil mode", | |||||
| "不支持的线圈模式", | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||
| @@ -333,7 +333,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput( | |||||
| { | { | ||||
| return failure( | return failure( | ||||
| LogicScanError::RegisterWriteFailed, | LogicScanError::RegisterWriteFailed, | ||||
| "failed to write " + config->address.toString(), | |||||
| "写入寄存器失败:" + config->address.toString(), | |||||
| {}, | {}, | ||||
| {}, | {}, | ||||
| node.id); | node.id); | ||||