| @@ -454,7 +454,7 @@ bool LadderRung::validateStructure(std::string *error) const | |||
| if (containsLineBreak(comment) | |||
| || comment.size() > ProjectLimits::kMaximumRungCommentBytes) | |||
| { | |||
| setError(error, "梯形图行注释必须是最多 128 个 UTF-8 字节的单行文本"); | |||
| setError(error, "网络注释必须是最多 128 个 UTF-8 字节的单行文本"); | |||
| return false; | |||
| } | |||
| if (cells.empty()) | |||
| @@ -531,6 +531,33 @@ bool LadderRung::validateForRunning(std::string *error) const | |||
| return true; | |||
| } | |||
| std::size_t ControlLogic::networkHeadIndex(std::size_t rung_index) const | |||
| { | |||
| if (rung_index >= rungs.size()) | |||
| { | |||
| return rungs.size(); | |||
| } | |||
| while (rung_index > 0U) | |||
| { | |||
| const std::string &upper_id = rungs[rung_index - 1U].id; | |||
| const std::string &lower_id = rungs[rung_index].id; | |||
| const bool connected_to_previous = std::any_of( | |||
| verticalConnections.cbegin(), | |||
| verticalConnections.cend(), | |||
| [&upper_id, &lower_id](const VerticalConnection &connection) | |||
| { | |||
| return connection.upperRungId == upper_id | |||
| && connection.lowerRungId == lower_id; | |||
| }); | |||
| if (!connected_to_previous) | |||
| { | |||
| break; | |||
| } | |||
| --rung_index; | |||
| } | |||
| return rung_index; | |||
| } | |||
| bool ControlLogic::validate( | |||
| const ProjectLimitSettings &limits, std::string *error) const | |||
| { | |||
| @@ -641,6 +668,17 @@ bool ControlLogic::validateStructure( | |||
| return false; | |||
| } | |||
| } | |||
| for (std::size_t row = 1U; row < rungs.size(); ++row) | |||
| { | |||
| if (!rungs[row].comment.empty() && networkHeadIndex(row) != row) | |||
| { | |||
| setError( | |||
| error, | |||
| "第 " + std::to_string(row + 1U) | |||
| + " 行不是网络首行,不能保存网络注释"); | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| @@ -175,6 +175,7 @@ struct ControlLogic | |||
| bool enabled = true; | |||
| std::vector<VerticalConnection> verticalConnections; | |||
| std::size_t networkHeadIndex(std::size_t rung_index) const; | |||
| bool validate( | |||
| const ProjectLimitSettings &limits, | |||
| std::string *error = nullptr) const; | |||
| @@ -590,6 +590,45 @@ bool LogicEditorService::rungsEqual( | |||
| || nodesEqual(*left.output, *right.output); | |||
| } | |||
| bool LogicEditorService::mergeNetworkComments( | |||
| ControlLogic *logic, std::string *error) | |||
| { | |||
| if (logic == nullptr) | |||
| { | |||
| if (error != nullptr) | |||
| { | |||
| *error = "未找到控制逻辑"; | |||
| } | |||
| return false; | |||
| } | |||
| for (std::size_t row = 1U; row < logic->rungs.size(); ++row) | |||
| { | |||
| const std::size_t head = logic->networkHeadIndex(row); | |||
| if (head == row || logic->rungs[row].comment.empty()) | |||
| { | |||
| continue; | |||
| } | |||
| std::string &head_comment = logic->rungs[head].comment; | |||
| std::string &branch_comment = logic->rungs[row].comment; | |||
| if (!head_comment.empty() && head_comment != branch_comment) | |||
| { | |||
| if (error != nullptr) | |||
| { | |||
| *error = "无法合并网络:第 " + std::to_string(head + 1U) | |||
| + " 行和第 " + std::to_string(row + 1U) | |||
| + " 行存在不同注释,请先统一或清空其中一条"; | |||
| } | |||
| return false; | |||
| } | |||
| if (head_comment.empty()) | |||
| { | |||
| head_comment = branch_comment; | |||
| } | |||
| branch_comment.clear(); | |||
| } | |||
| return true; | |||
| } | |||
| bool LogicEditorService::cellsEqual( | |||
| const LadderCell &left, const LadderCell &right) | |||
| { | |||
| @@ -691,6 +730,19 @@ const LadderRung *LogicEditorService::findRung( | |||
| return found == logic->rungs.cend() ? nullptr : &*found; | |||
| } | |||
| const LadderRung *LogicEditorService::findNetworkHeadRung( | |||
| const std::string &logic_id, const std::string &rung_id) const | |||
| { | |||
| const ControlLogic *logic = findLogic(logic_id); | |||
| if (logic == nullptr) | |||
| { | |||
| return nullptr; | |||
| } | |||
| const std::size_t row = rungIndex(*logic, rung_id); | |||
| const std::size_t head = logic->networkHeadIndex(row); | |||
| return head == logic->rungs.size() ? nullptr : &logic->rungs[head]; | |||
| } | |||
| const LadderCell *LogicEditorService::findCell( | |||
| const std::string &logic_id, | |||
| const std::string &rung_id, | |||
| @@ -1217,13 +1269,13 @@ LogicEditorResult LogicEditorService::removeRungs( | |||
| return {true, LogicEditorError::None, {}, rung_ids.front()}; | |||
| } | |||
| LogicEditorResult LogicEditorService::updateRungComment( | |||
| LogicEditorResult LogicEditorService::updateNetworkComment( | |||
| const std::string &logic_id, | |||
| const std::string &rung_id, | |||
| const std::string &comment) | |||
| { | |||
| const LadderRung *rung = findRung(logic_id, rung_id); | |||
| if (rung == nullptr) | |||
| const LadderRung *head = findNetworkHeadRung(logic_id, rung_id); | |||
| if (head == nullptr) | |||
| { | |||
| return failure(LogicEditorError::RungNotFound, "未找到梯形图行"); | |||
| } | |||
| @@ -1232,17 +1284,18 @@ LogicEditorResult LogicEditorService::updateRungComment( | |||
| { | |||
| return failure( | |||
| LogicEditorError::InvalidOperation, | |||
| "行注释必须是最多 128 个 UTF-8 字节的单行文本"); | |||
| "网络注释必须是最多 128 个 UTF-8 字节的单行文本"); | |||
| } | |||
| if (rung->comment == comment) | |||
| if (head->comment == comment) | |||
| { | |||
| return {true, LogicEditorError::None, {}, rung_id}; | |||
| return {true, LogicEditorError::None, {}, head->id}; | |||
| } | |||
| const std::string head_rung_id = head->id; | |||
| HistoryState before = captureState(); | |||
| Project &project = project_service_.editProject(); | |||
| editableRung(editableLogic(&project, logic_id), rung_id)->comment = comment; | |||
| editableRung(editableLogic(&project, logic_id), head_rung_id)->comment = comment; | |||
| recordHistory(std::move(before)); | |||
| return {true, LogicEditorError::None, {}, rung_id}; | |||
| return {true, LogicEditorError::None, {}, head_rung_id}; | |||
| } | |||
| LogicEditResult LogicEditorService::applyConditionAndAdvance( | |||
| @@ -1584,6 +1637,11 @@ LogicEditorResult LogicEditorService::setVerticalConnectionRange( | |||
| } | |||
| } | |||
| std::string error; | |||
| if (connected && !mergeNetworkComments(editable, &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| return failure(LogicEditorError::InvalidOperation, error); | |||
| } | |||
| if (!editable->validateStructure(project_service_.projectLimits(), &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| @@ -2472,6 +2530,11 @@ LogicClipboardPasteResult LogicEditorService::pasteClipboard( | |||
| } | |||
| } | |||
| std::string error; | |||
| if (!mergeNetworkComments(editable, &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| return {failure(LogicEditorError::InvalidOperation, error), {}, {}}; | |||
| } | |||
| if (!editable->validateStructure(project_service_.projectLimits(), &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| @@ -2687,6 +2750,12 @@ LogicClipboardPasteResult LogicEditorService::pasteClipboard( | |||
| } | |||
| } | |||
| std::string error; | |||
| if (!fragment.verticalConnections.empty() | |||
| && !mergeNetworkComments(editable, &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| return {failure(LogicEditorError::InvalidOperation, error), {}, {}}; | |||
| } | |||
| if (!editable->validateStructure(project_service_.projectLimits(), &error)) | |||
| { | |||
| rollbackEdit(std::move(before), modified_before); | |||
| @@ -165,6 +165,8 @@ public: | |||
| const ControlLogic *findLogic(const std::string &logic_id) const; | |||
| const LadderRung *findRung( | |||
| const std::string &logic_id, const std::string &rung_id) const; | |||
| const LadderRung *findNetworkHeadRung( | |||
| const std::string &logic_id, const std::string &rung_id) const; | |||
| const LadderCell *findCell( | |||
| const std::string &logic_id, | |||
| const std::string &rung_id, | |||
| @@ -209,7 +211,7 @@ public: | |||
| LogicEditorResult removeRungs( | |||
| const std::string &logic_id, | |||
| const std::vector<std::string> &rung_ids); | |||
| LogicEditorResult updateRungComment( | |||
| LogicEditorResult updateNetworkComment( | |||
| const std::string &logic_id, | |||
| const std::string &rung_id, | |||
| const std::string &comment); | |||
| @@ -323,6 +325,8 @@ private: | |||
| const ControlLogic &left, const ControlLogic &right); | |||
| static bool rungsEqual( | |||
| const LadderRung &left, const LadderRung &right); | |||
| static bool mergeNetworkComments( | |||
| ControlLogic *logic, std::string *error); | |||
| static bool cellsEqual( | |||
| const LadderCell &left, const LadderCell &right); | |||
| static bool nodesEqual(const LogicNode &left, const LogicNode &right); | |||
| @@ -1055,21 +1055,7 @@ void LogicEditorWidget::rebuildRowLayout(const ControlLogic &logic) | |||
| qreal next_top = kTop; | |||
| for (std::size_t row = 0U; row < logic.rungs.size(); ++row) | |||
| { | |||
| bool connected_to_previous = false; | |||
| if (row > 0U) | |||
| { | |||
| const std::string &upper_id = logic.rungs[row - 1U].id; | |||
| const std::string &lower_id = logic.rungs[row].id; | |||
| connected_to_previous = std::any_of( | |||
| logic.verticalConnections.cbegin(), | |||
| logic.verticalConnections.cend(), | |||
| [&upper_id, &lower_id](const VerticalConnection &connection) | |||
| { | |||
| return connection.upperRungId == upper_id | |||
| && connection.lowerRungId == lower_id; | |||
| }); | |||
| } | |||
| const bool network_head = row == 0U || !connected_to_previous; | |||
| const bool network_head = logic.networkHeadIndex(row) == row; | |||
| if (network_head) | |||
| { | |||
| next_top += kCommentBandHeight; | |||
| @@ -878,8 +878,8 @@ void MainWindow::configureActions() | |||
| }); | |||
| connect(ui_->deleteLogicAction, &QAction::triggered, | |||
| this, &MainWindow::deleteSelectedLogicObject); | |||
| connect(ui_->editRungCommentAction, &QAction::triggered, | |||
| this, &MainWindow::editSelectedRungComment); | |||
| connect(ui_->editNetworkCommentAction, &QAction::triggered, | |||
| this, &MainWindow::editSelectedNetworkComment); | |||
| addToolbarMenu( | |||
| ui_->logicToolBar, | |||
| tr("更多触点"), | |||
| @@ -994,7 +994,7 @@ void MainWindow::configureAppearance() | |||
| ui_->addAddAction->setIcon(makeUiIcon(UiIcon::Add)); | |||
| ui_->addSubAction->setIcon(makeUiIcon(UiIcon::Subtract)); | |||
| ui_->addCompareAction->setIcon(makeUiIcon(UiIcon::Compare)); | |||
| ui_->editRungCommentAction->setIcon(makeUiIcon(UiIcon::Comment)); | |||
| ui_->editNetworkCommentAction->setIcon(makeUiIcon(UiIcon::Comment)); | |||
| ui_->syntaxCheckAction->setIcon(makeUiIcon(UiIcon::SyntaxCheck)); | |||
| ui_->doubleCoilCheckAction->setIcon(makeUiIcon(UiIcon::Coil)); | |||
| ui_->deleteLogicAction->setIcon(makeUiIcon(UiIcon::Delete)); | |||
| @@ -1835,7 +1835,7 @@ void MainWindow::deleteLogicRung() | |||
| statusBar()->showMessage(tr("当前行已删除,竖线连接已重新整理"), 3000); | |||
| } | |||
| void MainWindow::editSelectedRungComment() | |||
| void MainWindow::editSelectedNetworkComment() | |||
| { | |||
| const std::string rung_id = logic_editor_widget_->selectedRungId(); | |||
| if (rung_id.empty()) | |||
| @@ -1843,9 +1843,9 @@ void MainWindow::editSelectedRungComment() | |||
| showProjectResult(tr("网络注释"), tr("请先选择一个梯形图网络"), false); | |||
| return; | |||
| } | |||
| const LadderRung *rung = logic_editor_service_.findRung( | |||
| const LadderRung *head = logic_editor_service_.findNetworkHeadRung( | |||
| current_logic_id_, rung_id); | |||
| if (rung == nullptr) | |||
| if (head == nullptr) | |||
| { | |||
| return; | |||
| } | |||
| @@ -1855,13 +1855,13 @@ void MainWindow::editSelectedRungComment() | |||
| tr("网络注释"), | |||
| tr("说明"), | |||
| QLineEdit::Normal, | |||
| fromUtf8(rung->comment), | |||
| fromUtf8(head->comment), | |||
| &accepted); | |||
| if (!accepted) | |||
| { | |||
| return; | |||
| } | |||
| const LogicEditorResult result = logic_editor_service_.updateRungComment( | |||
| const LogicEditorResult result = logic_editor_service_.updateNetworkComment( | |||
| current_logic_id_, rung_id, toUtf8(comment)); | |||
| if (!result.succeeded) | |||
| { | |||
| @@ -2453,7 +2453,7 @@ void MainWindow::updateModeUi(const QString &message) | |||
| ui_->addAddAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addSubAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addCompareAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->editRungCommentAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->editNetworkCommentAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->deleteLogicAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->newProjectAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->saveProjectAction->setEnabled(policy.allowsProjectEditing); | |||
| @@ -197,7 +197,7 @@ private: | |||
| /** 删除当前选中的梯形图行 */ | |||
| void deleteLogicRung(); | |||
| /** 编辑当前网络的注释 */ | |||
| void editSelectedRungComment(); | |||
| void editSelectedNetworkComment(); | |||
| /** 规整并检查当前梯形图 */ | |||
| void runLogicSyntaxCheck(); | |||
| /** 单独检查当前梯形图中的重复线圈输出 */ | |||
| @@ -364,7 +364,7 @@ | |||
| <addaction name="addNormallyOpenAction"/> | |||
| <addaction name="addNormallyClosedAction"/> | |||
| <addaction name="addNormalCoilAction"/> | |||
| <addaction name="editRungCommentAction"/> | |||
| <addaction name="editNetworkCommentAction"/> | |||
| <addaction name="separator"/> | |||
| <addaction name="syntaxCheckAction"/> | |||
| </widget> | |||
| @@ -1318,7 +1318,7 @@ | |||
| <string>在选中的空网格或横线处添加 D 值与常量比较条件</string> | |||
| </property> | |||
| </action> | |||
| <action name="editRungCommentAction"> | |||
| <action name="editNetworkCommentAction"> | |||
| <property name="text"> | |||
| <string>网络注释</string> | |||
| </property> | |||
| @@ -696,6 +696,28 @@ void testEdgeAndCommentBoundaries() | |||
| comment_rung.comment = "第一行\r第二行"; | |||
| require(!comment_rung.validateStructure(), "a rung comment containing CR must be rejected"); | |||
| ControlLogic commented_logic; | |||
| commented_logic.id = "commented-logic"; | |||
| commented_logic.name = "Commented logic"; | |||
| LadderRung head; | |||
| head.id = "head"; | |||
| head.name = "Head"; | |||
| head.comment = "Network comment"; | |||
| LadderRung branch; | |||
| branch.id = "branch"; | |||
| branch.name = "Branch"; | |||
| branch.comment = "Hidden branch comment"; | |||
| commented_logic.rungs = {head, branch}; | |||
| commented_logic.verticalConnections = { | |||
| {"comment-edge", "head", "branch", 0}}; | |||
| require( | |||
| commented_logic.networkHeadIndex(1U) == 0U | |||
| && !commented_logic.validateStructure(), | |||
| "a connected branch row must not persist a hidden network comment"); | |||
| commented_logic.rungs[1].comment.clear(); | |||
| require(commented_logic.validateStructure(), | |||
| "a connected network must be valid when only its head stores the comment"); | |||
| Project project = makeValidProject(); | |||
| project.registerComments = { | |||
| {RegisterAddress{RegisterArea::M, 0}, "启动按钮"}, | |||
| @@ -192,6 +192,85 @@ void testIndependentVerticalConnectionsAndNetworkSplit() | |||
| "the model must reject vertical edges between non-adjacent rows"); | |||
| } | |||
| void testNetworkCommentsFollowNetworkHeadsAndMergeAtomically() | |||
| { | |||
| Fixture fixture; | |||
| const std::string first = fixture.addRung(); | |||
| const std::string second = fixture.addRung(); | |||
| const std::string third = fixture.addRung(); | |||
| require( | |||
| fixture.editor.updateNetworkComment( | |||
| fixture.logicId, second, "下方网络注释").succeeded, | |||
| "an independent lower network must accept its own comment"); | |||
| fixture.editor.clearHistory(); | |||
| const LogicEditorResult merged = fixture.editor.setVerticalConnection( | |||
| fixture.logicId, first, second, 4, true); | |||
| const ControlLogic *logic = fixture.editor.findLogic(fixture.logicId); | |||
| require( | |||
| merged.succeeded && logic->rungs[0].comment == "下方网络注释" | |||
| && logic->rungs[1].comment.empty() | |||
| && fixture.editor.findNetworkHeadRung(fixture.logicId, second)->id | |||
| == first, | |||
| "merging a commented lower network into an empty upper network must move the comment to the new head"); | |||
| require( | |||
| fixture.editor.undo().succeeded | |||
| && fixture.editor.findRung(fixture.logicId, first)->comment.empty() | |||
| && fixture.editor.findRung(fixture.logicId, second)->comment | |||
| == "下方网络注释" | |||
| && fixture.editor.redo().succeeded, | |||
| "network merge comment movement must belong to the same undo transaction"); | |||
| fixture.editor.clearHistory(); | |||
| const LogicEditorResult edited_from_branch = | |||
| fixture.editor.updateNetworkComment( | |||
| fixture.logicId, second, "从支路编辑后的注释"); | |||
| require( | |||
| edited_from_branch.succeeded && edited_from_branch.id == first | |||
| && fixture.editor.findRung(fixture.logicId, first)->comment | |||
| == "从支路编辑后的注释" | |||
| && fixture.editor.findRung(fixture.logicId, second)->comment.empty(), | |||
| "editing from a branch row must update only the network head comment"); | |||
| require( | |||
| fixture.editor.updateNetworkComment( | |||
| fixture.logicId, third, "另一个网络注释").succeeded, | |||
| "the third independent network must accept a different comment"); | |||
| fixture.editor.clearHistory(); | |||
| fixture.projects.restoreModifiedState(false); | |||
| const LogicEditorResult conflict = fixture.editor.setVerticalConnection( | |||
| fixture.logicId, second, third, 4, true); | |||
| logic = fixture.editor.findLogic(fixture.logicId); | |||
| require( | |||
| !conflict.succeeded | |||
| && conflict.message.find("存在不同注释") != std::string::npos | |||
| && connectionAt(*logic, second, third, 4) == nullptr | |||
| && logic->rungs[0].comment == "从支路编辑后的注释" | |||
| && logic->rungs[2].comment == "另一个网络注释" | |||
| && !fixture.projects.isModified() && !fixture.editor.canUndo(), | |||
| "merging differently commented networks must fail without partial topology or history"); | |||
| require( | |||
| fixture.editor.updateNetworkComment( | |||
| fixture.logicId, third, "从支路编辑后的注释").succeeded, | |||
| "the lower network comment must be editable before a retry"); | |||
| fixture.editor.clearHistory(); | |||
| require( | |||
| fixture.editor.setVerticalConnection( | |||
| fixture.logicId, second, third, 4, true).succeeded | |||
| && fixture.editor.findRung(fixture.logicId, third)->comment.empty(), | |||
| "merging equal network comments must keep one comment at the head"); | |||
| const std::string connection_id = connectionAt( | |||
| *fixture.editor.findLogic(fixture.logicId), second, third, 4)->id; | |||
| require( | |||
| fixture.editor.removeVerticalConnections( | |||
| fixture.logicId, {connection_id}).succeeded | |||
| && fixture.editor.findRung(fixture.logicId, first)->comment | |||
| == "从支路编辑后的注释" | |||
| && fixture.editor.findRung(fixture.logicId, third)->comment.empty(), | |||
| "splitting a network must not duplicate its head comment"); | |||
| } | |||
| void testInsertRowSplitsVerticalEdges() | |||
| { | |||
| Fixture fixture; | |||
| @@ -1149,7 +1228,7 @@ void testWholeRowClipboardInsertionAndLimit() | |||
| source_node.succeeded | |||
| && fixture.editor.setHorizontalWireRange( | |||
| fixture.logicId, second, 0, 1, true).succeeded | |||
| && fixture.editor.updateRungComment( | |||
| && fixture.editor.updateNetworkComment( | |||
| fixture.logicId, first, "整行复制注释").succeeded | |||
| && fixture.editor.setVerticalConnection( | |||
| fixture.logicId, first, second, 2, true).succeeded, | |||
| @@ -1413,6 +1492,7 @@ int main() | |||
| { | |||
| testContinuousGridAndIndependentHorizontalWires(); | |||
| testIndependentVerticalConnectionsAndNetworkSplit(); | |||
| testNetworkCommentsFollowNetworkHeadsAndMergeAtomically(); | |||
| testInsertRowSplitsVerticalEdges(); | |||
| testDeleteRowMergesOnlyContinuousEdges(); | |||
| testParallelBranchCreatesConnectedVisualRow(); | |||
| @@ -128,6 +128,7 @@ Project makeExampleProject() | |||
| logic.verticalConnections = { | |||
| {"vertical-left", "rung-1", "rung-2", 0}, | |||
| {"vertical-right", "rung-1", "rung-2", 1}}; | |||
| logic.rungs[1].comment.clear(); | |||
| project.controlLogics.push_back(std::move(logic)); | |||
| project.registerComments.push_back({ | |||
| RegisterAddress{RegisterArea::M, 0}, "Start signal"}); | |||
| @@ -396,6 +397,21 @@ void testInvalidGridAndConnectionsAreRejected() | |||
| == ProjectStorageError::InvalidProject, | |||
| "duplicate edges at one row boundary must be rejected"); | |||
| QJsonObject hidden_comment = original; | |||
| logic = firstLogic(&hidden_comment); | |||
| rungs = logic.value(QStringLiteral("rungs")).toArray(); | |||
| rung = rungs.at(1).toObject(); | |||
| rung.insert(QStringLiteral("comment"), QStringLiteral("hidden branch comment")); | |||
| rungs.replace(1, rung); | |||
| logic.insert(QStringLiteral("rungs"), rungs); | |||
| replaceFirstLogic(&hidden_comment, logic); | |||
| const QString hidden_comment_path = directory.filePath( | |||
| "hidden-branch-comment.json"); | |||
| writeBytes(hidden_comment_path, QJsonDocument(hidden_comment).toJson()); | |||
| require(storage.load(hidden_comment_path.toStdString()).error | |||
| == ProjectStorageError::InvalidProject, | |||
| "a 2.0 project must reject comments stored on connected branch rows"); | |||
| QJsonObject non_adjacent = original; | |||
| logic = firstLogic(&non_adjacent); | |||
| edges = logic.value(QStringLiteral("verticalConnections")).toArray(); | |||
| @@ -564,11 +564,14 @@ void testLadderLayoutAndDragDeletion() | |||
| logic_id, lower, 0, 1, true).succeeded | |||
| && editor.setVerticalConnection( | |||
| logic_id, upper, lower, 2, true).succeeded | |||
| && editor.updateRungComment( | |||
| logic_id, upper, "主网络注释").succeeded | |||
| && editor.updateRungComment( | |||
| logic_id, lower, "支路注释不应重复").succeeded, | |||
| && editor.updateNetworkComment( | |||
| logic_id, lower, "主网络注释").succeeded, | |||
| "layout fixture must create a connected two-row network"); | |||
| require( | |||
| editor.findNetworkHeadRung(logic_id, lower)->id == upper | |||
| && editor.findRung(logic_id, upper)->comment == "主网络注释" | |||
| && editor.findRung(logic_id, lower)->comment.empty(), | |||
| "editing a branch row must store the comment only on the network head"); | |||
| editor.clearHistory(); | |||
| LogicEditorWidget widget(editor); | |||
| @@ -578,7 +581,6 @@ void testLadderLayoutAndDragDeletion() | |||
| QCoreApplication::processEvents(QEventLoop::AllEvents); | |||
| bool found_head_comment = false; | |||
| bool found_branch_comment = false; | |||
| for (QGraphicsItem *item : widget.scene()->items()) | |||
| { | |||
| auto *text = dynamic_cast<QGraphicsSimpleTextItem *>(item); | |||
| @@ -588,11 +590,9 @@ void testLadderLayoutAndDragDeletion() | |||
| } | |||
| found_head_comment = found_head_comment | |||
| || text->text() == QStringLiteral("主网络注释"); | |||
| found_branch_comment = found_branch_comment | |||
| || text->text() == QStringLiteral("支路注释不应重复"); | |||
| } | |||
| require(found_head_comment && !found_branch_comment, | |||
| "only the network-head comment must be rendered"); | |||
| require(found_head_comment, | |||
| "the comment edited from a branch must render above the network head"); | |||
| constexpr qreal left_bus = 60.0; | |||
| constexpr qreal cell_width = 96.0; | |||