Command that groups multiple operations as a single undo unit. Useful for complex operations that involve multiple steps but should be undone/redone as a single logical operation.
| 108 | |
| 109 | |
| 110 | class CompositeCommand(CommandBase): |
| 111 | """ |
| 112 | Command that groups multiple operations as a single undo unit. |
| 113 | |
| 114 | Useful for complex operations that involve multiple steps but should |
| 115 | be undone/redone as a single logical operation. |
| 116 | """ |
| 117 | |
| 118 | def __init__(self, description: str, commands: list['CommandBase']): |
| 119 | """ |
| 120 | Initialize composite command. |
| 121 | |
| 122 | Args: |
| 123 | description: Description of the composite operation |
| 124 | commands: List of commands to execute as a group |
| 125 | """ |
| 126 | super().__init__(description) |
| 127 | self.commands = commands |
| 128 | self.executed_commands = [] |
| 129 | |
| 130 | def execute(self) -> bool: |
| 131 | """Execute all commands, rolling back on failure.""" |
| 132 | print(f"\n=== COMPOSITE COMMAND EXECUTE START ===") |
| 133 | print(f"DEBUG: Executing composite command with {len(self.commands)} commands") |
| 134 | |
| 135 | self.executed_commands = [] |
| 136 | |
| 137 | for i, command in enumerate(self.commands): |
| 138 | print(f"DEBUG: Executing command {i+1}/{len(self.commands)}: {command.get_description()}") |
| 139 | result = command.execute() |
| 140 | print(f"DEBUG: Command {i+1} returned: {result}") |
| 141 | |
| 142 | if result: |
| 143 | command._mark_executed() |
| 144 | self.executed_commands.append(command) |
| 145 | print(f"DEBUG: Command {i+1} succeeded, added to executed list") |
| 146 | else: |
| 147 | print(f"DEBUG: Command {i+1} FAILED - rolling back {len(self.executed_commands)} executed commands") |
| 148 | # Rollback executed commands on failure |
| 149 | for j, executed in enumerate(reversed(self.executed_commands)): |
| 150 | print(f"DEBUG: Rolling back command {j+1}/{len(self.executed_commands)}: {executed.get_description()}") |
| 151 | rollback_result = executed.undo() |
| 152 | print(f"DEBUG: Rollback {j+1} returned: {rollback_result}") |
| 153 | executed._mark_undone() |
| 154 | print(f"DEBUG: Rollback complete, composite command failed") |
| 155 | print(f"=== COMPOSITE COMMAND EXECUTE END (FAILED) ===\n") |
| 156 | return False |
| 157 | |
| 158 | self._mark_executed() |
| 159 | print(f"DEBUG: All {len(self.commands)} commands succeeded") |
| 160 | print(f"=== COMPOSITE COMMAND EXECUTE END (SUCCESS) ===\n") |
| 161 | return True |
| 162 | |
| 163 | def undo(self) -> bool: |
| 164 | """Undo all executed commands in reverse order.""" |
| 165 | if not self._executed: |
| 166 | print(f"DEBUG: CompositeCommand.undo() - not executed, cannot undo") |
| 167 | return False |
no outgoing calls