Files
oak-editor/docs/zh/plans/riir/M2-oakundo.md
T
Mike-Solar 9b25772267 docs: module-split execution manuals for RIIR stage 1 (plans/riir/)
13 files: 00 overview, 01 two-layer adapter spec (init/free/func +
opaque handles + same-name adapter classes, frozen naming/ownership/
error/event rules), 02 dependency matrix + split order M1-M9 (from a
490-file include scan), 03 Google Test spec (per-C-API coverage,
roundtrip tests, leak counters), M1-M9 per-module manuals with frozen
C APIs (common/undo/node/timeline/codec/audio/render/task/plugin) and
the facade assembly-layer verdict.
2026-07-27 00:06:33 +08:00

4.4 KiB
Raw Blame History

M2 · oakundo 拆分手册

内容:engine/undo/UndoCommand、MultiUndoCommand、UndoStack)。 依赖:common 2、node/project.h 1 处undocommand.cpp)。 被依赖:node 4、timeline 1、render 1、plugin 2、capi 14。 拆分顺序第 2 位(近叶子)。

1. 目标形态

oakundo/
  include/oakundo/{undocommand.h, undostack.h, types.h, export.h}
  src/
  tests/  # oakundo_gtest

2. 冻结 C API

2.1 oakundo/undocommand.h

typedef struct OakUndoCommand OakUndoCommand;

/* 回调式命令(app 与跨模块命令的统一载体) */
typedef void (*oakundo_command_fn)(void *userdata);
OAKUNDO_API OakUndoCommand *oakundo_command_create(
	const char *name, oakundo_command_fn redo, oakundo_command_fn undo,
	oakundo_command_fn free_fn, void *userdata);
OAKUNDO_API OakUndoCommand *oakundo_command_create_multi(void);
OAKUNDO_API int  oakundo_command_multi_add_child(OakUndoCommand *multi,
	OakUndoCommand *child);
OAKUNDO_API int  oakundo_command_multi_child_count(
	const OakUndoCommand *multi);
OAKUNDO_API void oakundo_command_redo_now(OakUndoCommand *cmd);
OAKUNDO_API void oakundo_command_undo_now(OakUndoCommand *cmd);
OAKUNDO_API void oakundo_command_free(OakUndoCommand *cmd);  /* NULL no-op */

2.2 oakundo/undostack.h

typedef struct OakUndoStack OakUndoStack;
OAKUNDO_API OakUndoStack *oakundo_undostack_init(void *parent_qobject);
OAKUNDO_API void oakundo_undostack_free(OakUndoStack *self);

OAKUNDO_API void oakundo_undostack_push(OakUndoStack *self,
	OakUndoCommand *cmd, const char *name);
/* push_pre_executed:子命令已 redo 过,入栈不重复 redo(undo 分组用) */
OAKUNDO_API void oakundo_undostack_push_pre_executed(OakUndoStack *self,
	OakUndoCommand *cmd, const char *name);

OAKUNDO_API int  oakundo_undostack_can_undo(const OakUndoStack *self);
OAKUNDO_API int  oakundo_undostack_can_redo(const OakUndoStack *self);
OAKUNDO_API void oakundo_undostack_undo(OakUndoStack *self);
OAKUNDO_API void oakundo_undostack_redo(OakUndoStack *self);
OAKUNDO_API void oakundo_undostack_jump(OakUndoStack *self, int64_t index);
OAKUNDO_API void oakundo_undostack_clear(OakUndoStack *self);
OAKUNDO_API int64_t oakundo_undostack_count(const OakUndoStack *self);
OAKUNDO_API int64_t oakundo_undostack_index(const OakUndoStack *self);
OAKUNDO_API int  oakundo_undostack_command_text(OakUndoStack *self,
	int64_t row, char *buf, int buf_size);
OAKUNDO_API int  oakundo_undostack_command_is_done(OakUndoStack *self,
	int64_t row);
OAKUNDO_API void oakundo_undostack_update_actions(OakUndoStack *self);
/* QAction* 句柄(GUI 菜单绑定用,borrowed */
OAKUNDO_API void *oakundo_undostack_undo_action(OakUndoStack *self);
OAKUNDO_API void *oakundo_undostack_redo_action(OakUndoStack *self);

/* 事件(index_changed */
#define OAKUNDO_EVENT_INDEX_CHANGED 1
typedef void (*oakundo_event_fn)(int event_id, int64_t a, int64_t b,
	void *userdata);
OAKUNDO_API int64_t oakundo_undostack_subscribe(OakUndoStack *self,
	int event_id, oakundo_event_fn fn, void *userdata);
OAKUNDO_API void oakundo_unsubscribe(int64_t subscription_id);

3. 切割点(1 处)

undocommand.cpp include node/project.hget_relevant_project() 虚函数的 Project 类型)。 处理:UndoCommand::get_relevant_project() 的返回类型在 oakundo 内部改为不透明 void *oakundo 不解释它);node 侧(M3)在自己的 适配层把 void *olive::Project * 互转。不改语义—— Project* 本来就只是作为不透明身份被使用(修改标记归属)。

4. 消费侧适配(按 01 §2

  • node/4 处)、timeline/1)、render/1)、plugin/2): 各自放 adapter/undocommand.h,转发用到的方法子集。
  • src/capi/undo.cpp14 处):facade 的 undo 族实现改为转发 oakundo C API(或保持 facade 直链 oakundo——facade 是装配层, 裁决见 M9 §4,默认直链不绕圈)。

5. 测试(映射 03 §2/§3

  • 每条 API 正常+错误路径(NULL self、空 push 不入栈—— 空 MultiUndoCommand 被删除的既有行为必须有 TEST 钉死)。
  • push/undo/redo/jump/clear 全序列;command_text/is_done 边界行。
  • 事件:push 后 index_changed 触发且 a=新 indexunsubscribe 后不再触发。
  • 往返测试:C API 与适配类各做一遍 push-undo-redo,状态一致。
  • oakundo_debug_alive_count()init/free 配对无泄漏。