blob: c8eb1c8c4594c067bb2da4ae731703f0862af487 [file] [log] [blame]
Guido van Rossum504b0bf1999-01-02 21:28:54 +00001from Tkinter import *
Guido van Rossum504b0bf1999-01-02 21:28:54 +00002import SearchEngine
3from SearchDialogBase import SearchDialogBase
4
5def 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
13class 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
Guido van Rossumab6a08a1999-06-08 13:06:07 +000080 text.undo_block_start()
Guido van Rossum504b0bf1999-01-02 21:28:54 +000081 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()
Guido van Rossumf8c8cf82002-07-24 19:13:08 +000088 new = m.expand(repl)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000089 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
Guido van Rossumab6a08a1999-06-08 13:06:07 +0000102 text.undo_block_stop()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000103 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():
Tim Petersbc0e9102002-04-04 22:55:58 +0000109 return False
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000110 text = self.text
111 res = self.engine.search_text(text, None, ok)
112 if not res:
113 text.bell()
Tim Petersbc0e9102002-04-04 22:55:58 +0000114 return False
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000115 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
Tim Petersbc0e9102002-04-04 22:55:58 +0000121 return True
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000122
123 def do_replace(self):
124 prog = self.engine.getprog()
125 if not prog:
Tim Petersbc0e9102002-04-04 22:55:58 +0000126 return False
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000127 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:
Tim Petersbc0e9102002-04-04 22:55:58 +0000139 return False
Guido van Rossumf8c8cf82002-07-24 19:13:08 +0000140 new = m.expand(self.replvar.get())
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000141 text.mark_set("insert", first)
Guido van Rossum9745f5a1999-06-08 12:54:56 +0000142 text.undo_block_start()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000143 if m.group():
144 text.delete(first, last)
145 if new:
146 text.insert(first, new)
Guido van Rossum9745f5a1999-06-08 12:54:56 +0000147 text.undo_block_stop()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000148 self.show_hit(first, text.index("insert"))
149 self.ok = 0
Tim Petersbc0e9102002-04-04 22:55:58 +0000150 return True
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000151
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000152 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")