old_contents: # Copyright (c) 2015 Ultimaker B.V.
  # Uranium is released under the terms of the AGPLv3 or higher.
  
  from . import Operation
  
  ##  An operation that groups several other operations together.
  #
  #   The intent of this operation is to hide an underlying chain of operations
  #   from the user if they correspond to only one interaction with the user, such
  #   as an operation applied to multiple scene nodes or a re-arrangement of
  #   multiple items in the scene.
  class GroupedOperation(Operation.Operation):
      ##  Creates a new grouped operation.
      #
      #   The grouped operation is empty after its initialisation.
      def __init__(self):
          super().__init__()
          self._children = []
          self._finalised = False #Indicates if this operation is ever used. After that, it may no longer be modified.
  
      ##  Adds an operation to this group.
      #
      #   The operation will be undone together with the rest of the operations in
      #   this group.
      #   Note that when the order matters, the operations are undone in reverse
      #   order as the order in which they are added.
      def addOperation(self, op):
          if self._finalised:
              raise Exception("A grouped operation may not be modified after it is used.")
          self._children.append(op)
  
      ##  Undo all operations in this group.
      #
      #   The operations are undone in reverse order as the order in which they
      #   were added.
      def undo(self):
          for op in reversed(self._children):
              op.undo()
          self._finalised = True
  
      ##  Redoes all operations in this group.
      def redo(self):
          for op in self._children:
              op.redo()
          self._finalised = True
new_contents: # Copyright (c) 2015 Ultimaker B.V.
  # Uranium is released under the terms of the AGPLv3 or higher.
  
  from . import Operation
  
  ##  An operation that groups several other operations together.
  #
  #   The intent of this operation is to hide an underlying chain of operations
  #   from the user if they correspond to only one interaction with the user, such
  #   as an operation applied to multiple scene nodes or a re-arrangement of
  #   multiple items in the scene.
  class GroupedOperation(Operation.Operation):
      ##  Creates a new grouped operation.
      #
      #   The grouped operation is empty after its initialisation.
      def __init__(self):
          super().__init__()
          self._children = []
          self._finalised = False #Indicates if this operation is ever used. After that, it may no longer be modified.
  
      ##  Adds an operation to this group.
      #
      #   The operation will be undone together with the rest of the operations in
      #   this group.
      #   Note that when the order matters, the operations are undone in reverse
      #   order as the order in which they are added.
      def addOperation(self, op):
          if self._finalised:
              raise Exception("A grouped operation may not be modified after it is used.")
          self._children.append(op)
  
      ##  Undo all operations in this group.
      #
      #   The operations are undone in reverse order as the order in which they
      #   were added.
      def undo(self):
          for op in reversed(self._children):
              op.undo()
          self._finalised = True
  
      ##  Redoes all operations in this group.
      def redo(self):
          for op in self._children:
              op.redo()
          self._finalised = True
  
      ##  Merges this operation with another GroupOperation.
      #
      #   This prevents the user from having to undo multiple operations if they
      #   were not his operations.
      #
      #   The older operation must have the same number of child operations, and
      #   each pair of operations must succesfully merge, or the merge of the
      #   groupOperation will fail.
      #
      #   \param other The older GroupOperation to merge this with.
      #   \return A combination of the two group operations, or False if the operations
      #           can not be merged.
      def mergeWith(self, other):
          if type(other) is not GroupedOperation:
              return False
          if len(other._children) != len(self._children): #Must be operations on the same number of children.
              return False
  
          op = GroupedOperation()
          for (op1, op2) in zip(self._children, other._children):
              child_op = op1.mergeWith(op2)
              if not child_op:
                  return False
              op.addOperation(child_op)
          return op
  
subject: Implement merging of GroupedOperations