Update connect/disconnect action states.
[kaya.git] / lib / interaction / operation.rb
blob3ebd948fb7efcf5acd45e625cd8ef1ad2fe9eb85
1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 module Operation
9   attr_reader :undo_op
10   
11   def undo
12     undo_op.execute(:undoable => false) if undo_op
13   end
14 end
16 # Add new moves at the end of a history
17
18 class MoveOperation
19   include Operation
20   
21   def initialize(history, *items)
22     @history = history
23     @items = items
24   end
25   
26   def execute(opts = { })
27     index = @history.add_items(opts[:extra] || { }, *@items)
28     
29     if opts.fetch(:undoable, true)
30       @undo_op = TruncateOperation.new(@history, index)
31     end
32   end
33 end
35 # Truncate the history from the given index to
36 # the end
37
38 class TruncateOperation
39   include Operation
40   
41   def initialize(history, index)
42     @history = history
43     @index = index
44   end
45   
46   def undo
47     undo_op.execute(:undoable => false,
48                     :extra => { :go_to_end => false })
49   end
50   
51   def execute(opts = { })
52     items = @history.remove_items_at(@index, opts[:extra] || { })
53     if opts.fetch(:undoable, true)
54       @undo_op = MoveOperation.new(@history, *items)
55     end
56   end
57 end
59 class CompositeOperation
60   def initialize(*actions)
61     @actions = actions
62   end
63   
64   def undo
65     @actions.reverse.each do |action|
66       action.undo
67     end
68   end
69   
70   def execute(opts = { })
71     @actions.each do |action|
72       action.execute(opts)
73     end
74   end
75 end
77 module OperationInterface
78   class OperationBuilder
79     attr_reader :ops
80     def initialize(history)
81       @history = history
82       @ops = []
83     end
85     def method_missing(m, *args)
86       klass = eval(m.to_s.capitalize + "Operation")
87       @ops << klass.new(@history, *args)
88     end
89   end
90   
91   def operation(opts = { })
92     builder = OperationBuilder.new(self)
93     yield builder
94     ops = builder.ops
95     op = case ops.size
96     when 0
97       nil
98     when 1
99       ops.first
100     else
101       CompositeOperation.new(*ops)
102     end
103     operations << op if opts.fetch(:save, true)
104     op
105   end