diff --git a/docs/plan/XCUI_NewEditor收口重构计划_2026-04-17.md b/docs/plan/XCUI_NewEditor收口重构计划_2026-04-17.md index 7132b972..690f8a8f 100644 --- a/docs/plan/XCUI_NewEditor收口重构计划_2026-04-17.md +++ b/docs/plan/XCUI_NewEditor收口重构计划_2026-04-17.md @@ -52,6 +52,7 @@ - 已补跨窗口 `panelId` 唯一性校验 - 已补对应窗口工作区单元测试 - 已补 detached single-panel transfer 的 source root / open-visible 约束,避免脏 source 请求绕过可见性校验 + - 已补同窗口 `move/dock` 的 controller 级结果校验与回滚,避免 mutation 回归直接污染 window-set 状态 9. integration 测试构建模板已继续收口: - 已把 `tests/UI/Editor/integration` 叶子目标收敛到 shared helper @@ -547,6 +548,7 @@ - 已完成 `workspace duplicate nodeId` 校验与单元测试 - 已完成 `window-workspace` 跨窗口 `panelId` 重复校验与单元测试 - 已完成 detached single-panel transfer 对 `sourceNodeId` 与 `open/visible` 的约束补齐,并补单元测试 +- 已完成同窗口 `move/dock` 的结果校验与回滚防线补齐 - 尚未完成 transfer 前后 session/state 完整性约束 - 尚未完成 cross-window drag/drop 状态机约束收口 diff --git a/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp b/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp index 002c136b..5c6b2395 100644 --- a/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp +++ b/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp @@ -234,6 +234,7 @@ UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::MovePa } if (sourceWindowId == targetWindowId) { + const UIEditorWindowWorkspaceSet windowSetBefore = m_windowSet; UIEditorWindowWorkspaceState* window = FindMutableUIEditorWindowWorkspaceState(m_windowSet, sourceWindowId); if (window == nullptr) { @@ -261,6 +262,17 @@ UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::MovePa } m_windowSet.activeWindowId = std::string(targetWindowId); + const UIEditorWindowWorkspaceValidationResult validation = ValidateState(); + if (!validation.IsValid()) { + m_windowSet = windowSetBefore; + return BuildOperationResult( + UIEditorWindowWorkspaceOperationStatus::Rejected, + "Move produced invalid state: " + validation.message, + sourceWindowId, + targetWindowId, + panelId); + } + return BuildOperationResult( UIEditorWindowWorkspaceOperationStatus::Changed, "Panel moved within the same window.", @@ -344,6 +356,7 @@ UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::DockPa } if (sourceWindowId == targetWindowId) { + const UIEditorWindowWorkspaceSet windowSetBefore = m_windowSet; UIEditorWindowWorkspaceState* window = FindMutableUIEditorWindowWorkspaceState(m_windowSet, sourceWindowId); if (window == nullptr) { @@ -372,6 +385,17 @@ UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::DockPa } m_windowSet.activeWindowId = std::string(targetWindowId); + const UIEditorWindowWorkspaceValidationResult validation = ValidateState(); + if (!validation.IsValid()) { + m_windowSet = windowSetBefore; + return BuildOperationResult( + UIEditorWindowWorkspaceOperationStatus::Rejected, + "Dock produced invalid state: " + validation.message, + sourceWindowId, + targetWindowId, + panelId); + } + return BuildOperationResult( UIEditorWindowWorkspaceOperationStatus::Changed, "Panel docked within the same window.",