New release.
[rox-edit.git] / buffer.py
blobe3042fae7e645a30f1e0309fb2d9acb6ac8da11b
1 import rox
2 from rox import g
4 DELETE = 1
5 INSERT = 2
7 # As operations are performed, they are added to 'in_progress'.
8 # When complete, the whole group is added to undo_buffer.
10 class Buffer(g.TextBuffer):
11 "A buffer that deals with undo/redo."
12 action_nest_level = 0
14 def __init__(self):
15 g.TextBuffer.__init__(self, None)
16 self.in_progress = None
17 self.undo_buffer = []
18 self.redo_buffer = [] # Will be None during undo or redo
20 def start_undo_history(self):
21 def begin(buffer):
22 self.action_nest_level += 1
23 if self.action_nest_level == 1:
24 assert self.in_progress is None
25 self.in_progress = []
27 self.connect('begin-user-action', begin)
28 def end_action(buffer):
29 self.action_nest_level -= 1
30 assert self.action_nest_level >= 0
31 if self.action_nest_level == 0:
32 assert self.in_progress is not None
33 if self.in_progress:
34 self.undo_buffer.append(self.in_progress)
35 self.in_progress = None
36 self.connect('end-user-action', end_action)
37 self.connect('delete-range', self.delete_range)
38 self.connect('insert-text', self.insert_text)
40 def delete_range(self, buffer, start, end):
41 self.in_progress.append((INSERT,
42 start.get_offset(),
43 buffer.get_slice(start, end, g.TRUE)))
44 if self.redo_buffer:
45 self.redo_buffer = []
47 def insert_text(self, buffer, where, text, len):
48 text = text[:len] # PyGtk bug?
49 start = where.get_offset()
50 self.in_progress.append((DELETE,
51 start, start + len, text))
52 if self.redo_buffer:
53 self.redo_buffer = []
55 try:
56 g.TextBuffer(None).insert_at_cursor('hello')
57 except:
58 # Old version of pygtk
59 def insert(self, iter, text):
60 g.TextBuffer.insert(self, iter, text, -1)
61 def insert_at_cursor(self, text):
62 g.TextBuffer.insert_at_cursor(self, text, -1)
64 def do_action(self, op):
65 if op[0] == DELETE:
66 start = self.get_iter_at_offset(op[1])
67 end = self.get_iter_at_offset(op[2])
68 self.delete(start, end)
69 elif op[0] == INSERT:
70 start = self.get_iter_at_offset(op[1])
71 self.insert(start, op[2])
72 else:
73 rox.alert('Unknown entry in undo buffer!\n' + `op`)
75 def undo(self, hist = None):
76 if hist is None: hist = self.undo_buffer
78 if not hist:
79 g.gdk.beep()
80 return # Nothing to undo/redo
82 assert not self.in_progress
84 # List of actions to perform
85 group = hist.pop()
87 old_redo, self.redo_buffer = self.redo_buffer, None
89 try:
90 self.begin_user_action()
91 group.reverse()
92 for action in group:
93 self.do_action(action)
94 finally:
95 self.redo_buffer = old_redo
96 if hist is self.undo_buffer:
97 self.redo_buffer.append(self.in_progress)
98 else:
99 self.undo_buffer.append(self.in_progress)
100 self.in_progress = []
102 self.end_user_action()
104 def redo(self): self.undo(hist = self.redo_buffer)