Files
orisys-app/docs/architecture/studio-window-refactor-plan.zh.md
T
ykcheungab d477a4d8b7 接入 Studio 控件与菜单构建模块
将界面构建从主窗口移出,保留现有业务回调与标定路径。验证结果和完整门禁限制见 docs/architecture/studio-window-refactor-plan.zh.md。
2026-10-19 10:14:58 +08:00

194 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Studio 主窗口分步重构计划
目的:plan。范围:`apps/studio/src/orisys_studio/app_window.py` 及其直接调用方。
当前架构由 [Studio 架构](studio-architecture.md) 维护;本文件是唯一实施进度记录。
## 目标与约束
主窗口保留组件装配、跨功能信号连接、窗口几何及明确的关闭顺序。
按职责迁移现有实现,不增加产品功能、依赖、线程或全局状态容器。
会话、回放、布局、显示偏好和记录状态继续由现有控制器持有。
显示层只读取状态;录制与标定采样继续消费采集线程的数据,不依赖刷新频率。
启动、停止、暂停、异常处理、信号顺序及懒加载时机均属于行为保持边界。
关闭时保留预览关闭、采集回调解绑、分析取消与等待、采集和录制收尾、3D 释放的顺序。
测试和工具确实使用的旧入口可以暂留,但每一步必须说明保留原因并更新真实调用方。
不提交、不切换分支;排除已有 Autocal、测试修复文档及工作区归档修改。
## 顺序与验收
每步都先检查调用方及相关测试,完成后更新本计划和架构文档。
任务顺序为 S0 → S1 → S2 → S3 → S4 → S5 → S6;每一步均可独立审查。
### S0:基线与计划
- [x] 记录 HEAD、索引和已有修改,建立独立 scratch 证据目录。
- [x] 在改动前运行状态显示与主窗口相关测试。
基线:2026-10-18,`orisys-app` 的 `main`,HEAD `433b76e`。
源码为 3,181 行;`StudioMainWindow` 有 212 个方法,含属性访问器。
原架构文档的 2,309 行及“拆分已完成”属于历史状态。
### S1:状态显示
- [x] 新建 `status_presenter.py`,接收显示事实与目标控件,不接收整个窗口。
- [x] 迁移 phase、来源摘要、标定摘要、有效性及录制统计的格式化与显示。
- [x] 保留 `_record_stats` 注入入口,保证已有截图工具和 UI 检查仍有效。
涉及主窗口、新 Presenter 和定向测试。验收:实时视图不显示回放标题;分析结果保持自己的
传感器身份;未知、无标定、部分轴标定仍可区分;录制关闭中不显示完成,丢失计数完整。
验证:状态 Presenter 独立测试、`test_ui_smoke`、`test_replay_wiring` 和现有 UI 检查。
### S2:界面构建
- [x] 准备 `ui/window_ui.py` 和 `ui/window_menus.py`,先以独立窗口验证。
- [x] 接入 `ui/window_ui.py` 的控件和布局构建,保持控件身份、顺序及 parent。
- [x] 迁移菜单和 QAction 创建;由窗口显式连接功能操作。
- [x] 迁移对应文字与主题更新,保留必要属性兼容入口。
依赖 S1。涉及主窗口、UI 模块及实际调用方;面板构建和菜单构建分两批验收。
验证:`test_ui_elements`、`test_view_layout`、`test_sensor_switch_window`、主题与语言检查。
3D 仍在原时机创建,启动恢复顺序及保存的布局不变。
### S3:实时标定交互
- [ ] 提取 `live_calibration.py` 的选择保存、解析、确认及提交请求。
- [ ] 文件身份和匹配规则复用 `CalibrationService`;对话框通过窄接口访问。
- [ ] 设备确认、记录版本及采样仍走现有记录通道。
依赖 S2。验证:`test_live_calibration_dialog`、`test_calibration_service` 及确认事件测试。
导出不等于应用,应用请求不等于设备确认,序列号不匹配的处理不变。
### S4:分析配置
- [ ] 提取 `analysis_setup.py` 的对话框、裸视频工作目录和分析服务构造。
- [ ] 迁移 reference override 的所有权,保持现有保存和取消语义。
- [ ] `ReplayController` 继续负责执行、取消、缓存及结果选择,不吸收配置逻辑。
依赖 S3 的标定选择接口。验证:`test_bare_video_analysis`、`test_analysis_progress`、
`test_replay_wiring`;历史录制仍使用自身 chain,取消配置不改变当前结果。
### S5:运行协调与预览
- [ ] 先提取 `preview_controller.py`,负责设备和预览定时器生命周期。
- [ ] 再提取 `activity_coordinator.py`,统一按钮和快捷键的运行、暂停、停止规则。
- [ ] worker 操作通过 `SessionController`;关闭流程继续在窗口显式排列。
依赖 S4。两批分别验证 `test_session_controller`、`test_pause_controls`、
`test_transport_review` 和连接中停止、断开、异常、重复关闭场景。
普通停止保持非阻塞,退出等待资源结束;预览与采集不能争用相机。
### S6:显示入口与兼容桥收尾
- [ ] 将 2D/3D 的共同交付协调归入现有 `FrameView`,调用方显式传入显示上下文。
- [ ] 更新测试和工具为真实控制器接口,删除已无调用方的窗口转发。
- [ ] 核对依赖方向、无循环、线程归属和文档现状;运行完整门禁。
依赖 S5。验证:`test_shared_depth_scale`、`test_scene3d_frame_views`、回放定位与
显示设置重绘测试。2D/3D 使用同一帧;实时不覆盖回放;重绘不启动新分析。
结束条件是主窗口只承担约定职责,且所有相关检查通过,不以行数作为唯一标准。
## 验证记录
解释器使用 `.venv-build/Scripts/python.exe`。定向 pytest 显式使用独立的
`--basetemp` 和 `-p no:cacheprovider`;日志位于 `.scratch/studio-window-refactor/`。
每个迁移步骤运行对应检查;可交付批次运行 `tools/gate.ps1 -Task studio-window-refactor`。
文档使用工作区 `scripts/doc_lint.py` 和 `scripts/doc_count.py`,不扩大基线。
### 2026-10-19:S2 接线
以 `main` 的 `c6c16df` 为基准,接入已准备的两个 UI 模块;主窗口从 3,070 行减至
2,894 行。10 个控件和 35 个菜单、action 属性保留同一对象引用;18 处菜单业务回调及
控制器绑定仍在窗口。主题与文字更新委托 UI 模块,reset 目标、pause 状态仍沿用原逻辑。
FrameView、共享 domain latch 和曲线 store 在控制器接线前绑定,偏好恢复顺序不变。
只改动窗口的构造、菜单构建、菜单勾选、文字和主题刷新五个方法;其余方法的 AST 一致,
最新标定读取、应用和关闭路径未迁移。S3–S6 保持待实施。
改动前定向检查为 46 passed;接线后加上三个集成检查为 49 passed。
覆盖控件身份、菜单单次调用、主题与语言刷新、实时与回放的 reset 目标,以及既有布局、
暂停和标定对话框。首次新增断言误将菜单与按钮的不同文案视为相同,已按原契约修正。
串行门禁的 lint 通过,UI 检查为 632 checks、0 failures;共享层为 461 passed、
18 skipped、3 deselected、15 failed,涉及 SDK 映射文件缺失及几何尺寸不一致。
Studio 在垃圾回收期间访问冲突退出,无 JUnit 报告。整套门禁未通过,原因尚未完全确认。
扩展界面检查为 131 passed、1 failed,失败是分析停止后的即时状态断言。
该用例及崩溃所在的三个布局场景,在旧、新主窗口隔离运行均为 4 passed,未复现整套异常。
旧主窗口整套对照长时间无进度后已中断,不能据此判定原因。未修改失败断言或扩大基线。
临时禁用局部主题刷新时,新增测试按预期失败;仅在测试进程注入,源码未改动。
环境为 Windows、Python 3.10.19、offscreen Qt;真实设备、可见桌面和硬件 GL 未验证。
文档检查无新增问题,原架构长段落债务仍保留。证据位于
`.scratch/studio-window-refactor/20261019-095028/` 和 `gate-20261019T015301Z/`。
另一个进程的 Autocal 修改含暂存项,全部排除;本批六个文件未暂存,根仓库未修改。
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File tools/gate.ps1 -Task studio-window-refactor -LintBase HEAD -Serial
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests/test_ui_smoke.py apps/studio/tests/test_ui_elements.py apps/studio/tests/test_sensor_switch_window.py -m 'not timing' -o faulthandler_timeout=60 -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-095028\pytest-ui-focused --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-095028\ui-focused.xml
```
### 2026-10-19:S2 模块准备,接线延期
用户要求避开另一个进程正在修改的标定配置读取和应用路径,本批只新增模块及独立测试,
不编辑 `app_window.py`、现有面板、标定服务、控制器或配置文件。
基准为 `main` 的 `a0c13c1` 加当时工作区修改;读取的主窗口快照留在本批 scratch。
`WindowUi` 创建中央控件、四个面板及布局,提供局部主题和文字更新。
`WindowMenus` 创建 QAction、快捷键、菜单组和勾选初值,提供静态文字及主题/语言勾选同步。
两者均不保存偏好、不绑定业务回调,不启动设备、分析或 3D;真实控件复用现有实现。
当前主窗口仍走原来的构建路径,因此不能宣称 S2 已完成迁移。
未来接线前重新核对并行标定改动,再按顺序替换布局和菜单构建。
共享 domain latch、FrameView、曲线 store、业务信号和初始偏好恢复由窗口显式装配;
第一次呈现前完成绑定。菜单初值先于业务信号连接;reset 的目标文字、pause 状态及操作可用性
仍由现有控制器和窗口同步。兼容属性引用同一批控件,不另造重复面板。
新增 `test_window_surfaces.py` 和现有 `test_studio_binding_purity.py` 为 13 passed,
测试使用临时的空 sensor catalog,不扫描正在修改的真实配置目录。
还核对了 35 个菜单与 action 属性与起始快照一致;临时取消主题组互斥后测试能发现错误,
随后原样恢复。新增文件 lint 通过,文档检查无新增问题;主窗口与起始快照逐字节一致。
本批仅证明模块可独立使用;接线后的主窗口全套回归、真实桌面与设备验证仍待执行。
日志和 XML 位于 `.scratch/studio-window-refactor/20261019-094111/`,最终结果为 `final.xml`。
```powershell
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests/test_window_surfaces.py apps/studio/tests/test_studio_binding_purity.py -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-094111\pytest-final --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-094111\final.xml
```
### 2026-10-18:S1 接线与历史验证
2026-10-18:S0 和 S1 已实施。改动前后同一组 `test_ui_smoke` 与
`test_replay_wiring` 均为 125 passed;新增 Presenter 独立测试为 19 passed。
主窗口暂为 3,052 行;状态显示已迁出,S2–S6 尚未实施。
首次完整门禁:lint、共享层(467 passed、18 skipped、3 deselected)及 UI 检查
(632 checks、0 failures)通过;Studio 为 548 passed、19 skipped、2 failed。
失败分别是 `test_adopting_a_box_result_never_flashes_the_overlay_refusal` 的两次绘制,
以及 `test_the_replay_view_loads_a_recording_and_scrubs_it` 的录制目录缺失。
两项在重构前后隔离运行均通过;重构前主窗口的完整顺序对照为 550 passed、19 skipped。
没有修改回放实现、测试断言或失败基线来消除这些失败;其发生条件尚未确认。
当前主窗口的最终串行 Studio 复测为 550 passed、19 skipped,与旧主窗口完整对照一致。
S1 本批检查完成,S2 尚未开始;首次门禁失败报告仍保留,不改写为通过。
UI 检查虽然断言通过,日志另有 `asset_rejected: this coordinator has been closed` 的
异步加载回调异常;其复现条件未确认,S5 的关闭流程验收需要复核。
本批使用 Windows、Python 3.10.19 和 offscreen Qt,不能作为真实设备、可见桌面操作
或硬件 GL 验证。测试反转了标定 fallback 判断,7 项相关用例中 2 项发现错误;
随后按字节恢复源码。197 个相关源码和测试文件的 SHA-256 在最终收尾比较中完全一致。
文档门禁无新增问题;架构文档仍保留一项已登记的历史长段落债务,没有扩大基线。
实际执行的完整检查如下,工作目录为 `D:\orisys_ws\orisys-app`;独立日志和 XML 留在
`.scratch/studio-window-refactor/20261018-200221/`,首次门禁汇总位于相邻的
`gate-20261018T120931Z/summary.md`。这些是本地证据,未纳入版本控制。
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File tools\gate.ps1 -Task studio-window-refactor
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests -m 'not timing' -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261018-200221\pytest-final-studio --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261018-200221\final-studio.xml
```
并行任务将 App HEAD 从 `433b76e` 更新至 `cf3e638`,未改动本次主窗口基准;
相关回放分析修改不属于本批。
根仓库的计划索引和 inventory 登记被并行任务纳入 `bf44125`,根仓库目前无本批未提交修改。
本次没有执行提交、暂存或历史改写;产品仓库的五个交付文件保持未暂存。