Undo
----

Actions can be categorised as:
 Data Actions:
 - Add n channels before channel x : 
     remove channels x'..(x'+n-1)
 - Remove n channels starting from x:
     add n channels before x'
     set saved data on added channels
 - Insert n samples at x:
     remove samples x'..(x'+n-1)
 - Remove n samples at x:
     insert n samples at x'
     set saved data on added samples
 - Set data - n samples on channel c at x:
     set n saved samples on channel c at x
 - Change sample rate:
     old sample rate
 - Change bits:
     old bits

 UI actions:
 - Select:
     old selection state
 - View plugin:
     old view plugin
 - Time mode:
     old time mode
 - Vertical scale:
     old vertical scale

 - A combination of the above

Operations are pushed on a stack
Undo pops off stack

Compound actions can be achieved using begin/end markers in the stack
 - undoing a compound action means undo from end marker until corresponding
 begin marker (accounting for nested actions)

Limit stack size to ~10 (compound) operations.
  What about limit by saved data size??

Save undo data in tempfile - (could preserve across sessions (risky) )


Redo
----

When popping off undo stack, push inverse action (original operation) onto
redo stack.

New operations clear redo stack.



Implementation
--------------

Action:
  string: displayName

ChannelsAddAction: 
  int: startChannel
  int: numChannels

ChannelsRemoveAction
  int: startChannel
  int: numChannels
  Sample[numChannels][len]: data

InsertAction
  int: start
  int: length
 
RemoveAction
  int: start
  int: length
  Sample[n][length]: data

SetDataAction
  int: channel
  int: start
  int: length
  Sample[length]: data

SetSampleRateAction
  int: sampleRate

SetBitsAction
  int: bits

CompoundAction
  List<Action>: actions


Data has:
  Stack<Action> : undoActions
  Stack<Action> : redoActions
  Stack<Action> : compoundActions
  Stack<Action>*: activeActionStack

Data::Data
  clear stacks
  activeActionStack = &undoActions

Data::action
  activeActionStack->push(action(inverse data))


Data::undo
  activeActionStack = &redoActions
  a = undoActions.pop();
  a.apply(self);
  activeActionStack = &undoActions

Data::beginCompoundAction

Data::endCompoundAction

Plugin::action
  data->beginCompoundAction("name")
  ...
  data->endCompoundAction()


CompoundAction::apply
  data->beginCompoundAction("name") // redo set
  for a in actions.reverse():
    a.apply(data)
  data->endCompoundAction()
  
