Move match inside match_info in MatchHandler.
[kaya.git] / lib / interaction / history.rb
blob2471f61dcc90d691008f7be171fc604a318e9681
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 require 'observer_utils.rb'
9 require 'interaction/operation'
10 require 'interaction/operation_history'
12 class History
13   include Enumerable
14   include Observable
15   include OperationInterface
16   
17   attr_reader :current
18   attr_reader :operations
19   
20   class Item < Struct.new(:state, :move)
21     attr_accessor :text
22   end
23   OutOfBound = Class.new(Exception)
25   def initialize(state)
26     @history = [Item.new(state.dup, nil)]
27     @current = 0
28     @operations = OperationHistory.new
29   end
30   
31   def each
32     @history.each {|item| yield item.state, item.move }
33   end
34   
35   def add_move(state, move, opts = { })
36     op = operation do |op|
37       op.truncate(@current + 1)
38       item = Item.new(state.dup, move)
39       item.text = opts[:text] if opts[:text]
40       op.move(item)
41     end
42     op.execute :extra => opts
43   end
44   
45   def forward
46     raise OutOfBound if @current >= @history.size - 1
47     @current += 1
48     item = @history[@current]
49     
50     fire :current_changed
51     [item.state, item.move]
52   end
53   
54   def back
55     raise OutOfBound if @current <= 0
56     move = @history[@current].move
57     @current -= 1
58     
59     fire :current_changed
60     [@history[@current].state, move]
61   end
62   
63   def go_to(index)
64     if index != @current
65       item = self[index]
66       @current = index
67       fire :current_changed
68       [item.state, item.move]
69     end
70   end
71   
72   def go_to_last
73     go_to(size - 1)
74   end
75   
76   def go_to_first
77     go_to(0)
78   end
79   
80   def state
81     @history[current].state
82   end
83   
84   def state=(value)
85     @history[current].state = value
86     fire :force_update
87   end
88   
89   def set_item(state, move)
90     @history[current] = Item.new(state, move)
91     fire :force_update
92   end
93   
94   def move
95     @history[current].move
96   end
97   
98   def undo!
99     op = @operations.undo_operation
100     if op
101       op.undo
102     end
103   end
104   
105   def redo!
106     op = @operations.redo_operation
107     if op
108       op.execute
109     end
110   end
111   
112   def size
113     @history.size
114   end
115   
116   def [](index)
117     if index >= @history.size || index < 0
118       raise OutOfBound 
119     end
120     @history[index]
121   end
122   
123   # item interface
124   
125   def add_items(opts, *items)
126     @history += items
127     old_current = @current
128     old_state = state
129     @current = @history.size - 1  if opts.fetch(:go_to_end, true)
130     fire :new_move => {
131       :old_current => old_current,
132       :old_state => old_state,
133       :state => state,
134       :opts => opts }
135     @current
136   end
137   
138   def remove_items_at(index)
139     @current = index.pred
140     fire :current_changed
141     
142     items = @history[index..-1]
143     @history = @history[0...index]
144     @current = if @current >= index
145       index.pred
146     else
147       @current
148     end
149     fire :truncate => @current
150     items
151   end
152   
153   def current=(value)
154     @current = value
155   end