|
1 from Tkinter import * |
|
2 import SearchEngine |
|
3 from SearchDialogBase import SearchDialogBase |
|
4 |
|
5 def replace(text): |
|
6 root = text._root() |
|
7 engine = SearchEngine.get(root) |
|
8 if not hasattr(engine, "_replacedialog"): |
|
9 engine._replacedialog = ReplaceDialog(root, engine) |
|
10 dialog = engine._replacedialog |
|
11 dialog.open(text) |
|
12 |
|
13 class ReplaceDialog(SearchDialogBase): |
|
14 |
|
15 title = "Replace Dialog" |
|
16 icon = "Replace" |
|
17 |
|
18 def __init__(self, root, engine): |
|
19 SearchDialogBase.__init__(self, root, engine) |
|
20 self.replvar = StringVar(root) |
|
21 |
|
22 def open(self, text): |
|
23 SearchDialogBase.open(self, text) |
|
24 try: |
|
25 first = text.index("sel.first") |
|
26 except TclError: |
|
27 first = None |
|
28 try: |
|
29 last = text.index("sel.last") |
|
30 except TclError: |
|
31 last = None |
|
32 first = first or text.index("insert") |
|
33 last = last or first |
|
34 self.show_hit(first, last) |
|
35 self.ok = 1 |
|
36 |
|
37 def create_entries(self): |
|
38 SearchDialogBase.create_entries(self) |
|
39 self.replent = self.make_entry("Replace with:", self.replvar) |
|
40 |
|
41 def create_command_buttons(self): |
|
42 SearchDialogBase.create_command_buttons(self) |
|
43 self.make_button("Find", self.find_it) |
|
44 self.make_button("Replace", self.replace_it) |
|
45 self.make_button("Replace+Find", self.default_command, 1) |
|
46 self.make_button("Replace All", self.replace_all) |
|
47 |
|
48 def find_it(self, event=None): |
|
49 self.do_find(0) |
|
50 |
|
51 def replace_it(self, event=None): |
|
52 if self.do_find(self.ok): |
|
53 self.do_replace() |
|
54 |
|
55 def default_command(self, event=None): |
|
56 if self.do_find(self.ok): |
|
57 self.do_replace() |
|
58 self.do_find(0) |
|
59 |
|
60 def replace_all(self, event=None): |
|
61 prog = self.engine.getprog() |
|
62 if not prog: |
|
63 return |
|
64 repl = self.replvar.get() |
|
65 text = self.text |
|
66 res = self.engine.search_text(text, prog) |
|
67 if not res: |
|
68 text.bell() |
|
69 return |
|
70 text.tag_remove("sel", "1.0", "end") |
|
71 text.tag_remove("hit", "1.0", "end") |
|
72 line = res[0] |
|
73 col = res[1].start() |
|
74 if self.engine.iswrap(): |
|
75 line = 1 |
|
76 col = 0 |
|
77 ok = 1 |
|
78 first = last = None |
|
79 # XXX ought to replace circular instead of top-to-bottom when wrapping |
|
80 text.undo_block_start() |
|
81 while 1: |
|
82 res = self.engine.search_forward(text, prog, line, col, 0, ok) |
|
83 if not res: |
|
84 break |
|
85 line, m = res |
|
86 chars = text.get("%d.0" % line, "%d.0" % (line+1)) |
|
87 orig = m.group() |
|
88 new = m.expand(repl) |
|
89 i, j = m.span() |
|
90 first = "%d.%d" % (line, i) |
|
91 last = "%d.%d" % (line, j) |
|
92 if new == orig: |
|
93 text.mark_set("insert", last) |
|
94 else: |
|
95 text.mark_set("insert", first) |
|
96 if first != last: |
|
97 text.delete(first, last) |
|
98 if new: |
|
99 text.insert(first, new) |
|
100 col = i + len(new) |
|
101 ok = 0 |
|
102 text.undo_block_stop() |
|
103 if first and last: |
|
104 self.show_hit(first, last) |
|
105 self.close() |
|
106 |
|
107 def do_find(self, ok=0): |
|
108 if not self.engine.getprog(): |
|
109 return False |
|
110 text = self.text |
|
111 res = self.engine.search_text(text, None, ok) |
|
112 if not res: |
|
113 text.bell() |
|
114 return False |
|
115 line, m = res |
|
116 i, j = m.span() |
|
117 first = "%d.%d" % (line, i) |
|
118 last = "%d.%d" % (line, j) |
|
119 self.show_hit(first, last) |
|
120 self.ok = 1 |
|
121 return True |
|
122 |
|
123 def do_replace(self): |
|
124 prog = self.engine.getprog() |
|
125 if not prog: |
|
126 return False |
|
127 text = self.text |
|
128 try: |
|
129 first = pos = text.index("sel.first") |
|
130 last = text.index("sel.last") |
|
131 except TclError: |
|
132 pos = None |
|
133 if not pos: |
|
134 first = last = pos = text.index("insert") |
|
135 line, col = SearchEngine.get_line_col(pos) |
|
136 chars = text.get("%d.0" % line, "%d.0" % (line+1)) |
|
137 m = prog.match(chars, col) |
|
138 if not prog: |
|
139 return False |
|
140 new = m.expand(self.replvar.get()) |
|
141 text.mark_set("insert", first) |
|
142 text.undo_block_start() |
|
143 if m.group(): |
|
144 text.delete(first, last) |
|
145 if new: |
|
146 text.insert(first, new) |
|
147 text.undo_block_stop() |
|
148 self.show_hit(first, text.index("insert")) |
|
149 self.ok = 0 |
|
150 return True |
|
151 |
|
152 def show_hit(self, first, last): |
|
153 text = self.text |
|
154 text.mark_set("insert", first) |
|
155 text.tag_remove("sel", "1.0", "end") |
|
156 text.tag_add("sel", first, last) |
|
157 text.tag_remove("hit", "1.0", "end") |
|
158 if first == last: |
|
159 text.tag_add("hit", first) |
|
160 else: |
|
161 text.tag_add("hit", first, last) |
|
162 text.see("insert") |
|
163 text.update_idletasks() |
|
164 |
|
165 def close(self, event=None): |
|
166 SearchDialogBase.close(self, event) |
|
167 self.text.tag_remove("hit", "1.0", "end") |