From 52ef8a6042f43993a5c010725b76f263cc254b84 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 9 Jul 2023 22:29:49 +1000 Subject: [PATCH] Fix critical undo sync bug related to invoking instead of executing. See notes. Currently, the undo system works by wrapping the execute operator. What was not considered was that execute() isn't the only entry point to operators. Operators can be invoked. If an invoked operator calls a bpy.ops.bim.something in its invoke() function, then bpy.ops.bim.something will start and finish its own transaction, and then when the invoke finishes and finally runs execute(), another transaction will be started and finished. This means that we get at least one extra transaction logged (one per any call to bpy.ops.bim.foo in invoke()). This mismatch of number of transactions and undo stack means that when the user presses ctrl-z, the undo doesn't actually occur. This leads to a sync bug. To be safe, all IFC invokes must be wrapped. This will take some time to review so expect another commit soon. --- src/blenderbim/blenderbim/bim/ifc.py | 7 +++++-- src/blenderbim/blenderbim/bim/module/geometry/operator.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index 0542b20512..fa20886959 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -400,7 +400,7 @@ class IfcStore: ) @staticmethod - def execute_ifc_operator(operator, context): + def execute_ifc_operator(operator, context, is_invoke=False): is_top_level_operator = not bool(IfcStore.current_transaction) if is_top_level_operator: @@ -411,7 +411,10 @@ class IfcStore: else: operator.transaction_key = IfcStore.current_transaction - result = getattr(operator, "_execute")(context) + if is_invoke: + result = getattr(operator, "_invoke")(context, None) + else: + result = getattr(operator, "_execute")(context) if is_top_level_operator: IfcStore.get_file().end_transaction() diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index ef2f56c6c0..c006963f4d 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -1323,6 +1323,9 @@ class OverrideModeSetEdit(bpy.types.Operator): return {"FINISHED"} def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, is_invoke=True) + + def _invoke(self, context, event): if not tool.Ifc.get(): return bpy.ops.object.mode_set(mode="EDIT", toggle=True) return self.execute(context) @@ -1372,6 +1375,9 @@ class OverrideModeSetObject(bpy.types.Operator): row.label(text="No Geometry Found: Object will revert to previous state.") def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, is_invoke=True) + + def _invoke(self, context, event): self.is_valid = True self.should_save = True