home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / REPLACEDIALOG.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  6.0 KB  |  189 lines

  1. import string
  2. import os
  3. import re
  4. import fnmatch
  5. from Tkinter import *
  6. import tkMessageBox
  7. import SearchEngine
  8. from SearchDialogBase import SearchDialogBase
  9.  
  10. def replace(text):
  11.     root = text._root()
  12.     engine = SearchEngine.get(root)
  13.     if not hasattr(engine, "_replacedialog"):
  14.         engine._replacedialog = ReplaceDialog(root, engine)
  15.     dialog = engine._replacedialog
  16.     dialog.open(text)
  17.  
  18. class ReplaceDialog(SearchDialogBase):
  19.  
  20.     title = "Replace Dialog"
  21.     icon = "Replace"
  22.  
  23.     def __init__(self, root, engine):
  24.         SearchDialogBase.__init__(self, root, engine)
  25.         self.replvar = StringVar(root)
  26.  
  27.     def open(self, text):
  28.         SearchDialogBase.open(self, text)
  29.         try:
  30.             first = text.index("sel.first")
  31.         except TclError:
  32.             first = None
  33.         try:
  34.             last = text.index("sel.last")
  35.         except TclError:
  36.             last = None
  37.         first = first or text.index("insert")
  38.         last = last or first
  39.         self.show_hit(first, last)
  40.         self.ok = 1
  41.  
  42.     def create_entries(self):
  43.         SearchDialogBase.create_entries(self)
  44.         self.replent = self.make_entry("Replace with:", self.replvar)
  45.  
  46.     def create_command_buttons(self):
  47.         SearchDialogBase.create_command_buttons(self)
  48.         self.make_button("Find", self.find_it)
  49.         self.make_button("Replace", self.replace_it)
  50.         self.make_button("Replace+Find", self.default_command, 1)
  51.         self.make_button("Replace All", self.replace_all)
  52.  
  53.     def find_it(self, event=None):
  54.         self.do_find(0)
  55.  
  56.     def replace_it(self, event=None):
  57.         if self.do_find(self.ok):
  58.             self.do_replace()
  59.  
  60.     def default_command(self, event=None):
  61.         if self.do_find(self.ok):
  62.             self.do_replace()
  63.             self.do_find(0)
  64.  
  65.     def replace_all(self, event=None):
  66.         prog = self.engine.getprog()
  67.         if not prog:
  68.             return
  69.         repl = self.replvar.get()
  70.         text = self.text
  71.         res = self.engine.search_text(text, prog)
  72.         if not res:
  73.             text.bell()
  74.             return
  75.         text.tag_remove("sel", "1.0", "end")
  76.         text.tag_remove("hit", "1.0", "end")
  77.         line = res[0]
  78.         col = res[1].start()
  79.         if self.engine.iswrap():
  80.             line = 1
  81.             col = 0
  82.         ok = 1
  83.         first = last = None
  84.         # XXX ought to replace circular instead of top-to-bottom when wrapping
  85.         text.undo_block_start()
  86.         while 1:
  87.             res = self.engine.search_forward(text, prog, line, col, 0, ok)
  88.             if not res:
  89.                 break
  90.             line, m = res
  91.             chars = text.get("%d.0" % line, "%d.0" % (line+1))
  92.             orig = m.group()
  93.             new = self._expand(m, repl)
  94.             i, j = m.span()
  95.             first = "%d.%d" % (line, i)
  96.             last = "%d.%d" % (line, j)
  97.             if new == orig:
  98.                 text.mark_set("insert", last)
  99.             else:
  100.                 text.mark_set("insert", first)
  101.                 if first != last:
  102.                     text.delete(first, last)
  103.                 if new:
  104.                     text.insert(first, new)
  105.             col = i + len(new)
  106.             ok = 0
  107.         text.undo_block_stop()
  108.         if first and last:
  109.             self.show_hit(first, last)
  110.         self.close()
  111.  
  112.     def do_find(self, ok=0):
  113.         if not self.engine.getprog():
  114.             return 0
  115.         text = self.text
  116.         res = self.engine.search_text(text, None, ok)
  117.         if not res:
  118.             text.bell()
  119.             return 0
  120.         line, m = res
  121.         i, j = m.span()
  122.         first = "%d.%d" % (line, i)
  123.         last = "%d.%d" % (line, j)
  124.         self.show_hit(first, last)
  125.         self.ok = 1
  126.         return 1
  127.  
  128.     def do_replace(self):
  129.         prog = self.engine.getprog()
  130.         if not prog:
  131.             return 0
  132.         text = self.text
  133.         try:
  134.             first = pos = text.index("sel.first")
  135.             last = text.index("sel.last")
  136.         except TclError:
  137.             pos = None
  138.         if not pos:
  139.             first = last = pos = text.index("insert")
  140.         line, col = SearchEngine.get_line_col(pos)
  141.         chars = text.get("%d.0" % line, "%d.0" % (line+1))
  142.         m = prog.match(chars, col)
  143.         if not prog:
  144.             return 0
  145.         new = self._expand(m, self.replvar.get())
  146.         text.mark_set("insert", first)
  147.         text.undo_block_start()
  148.         if m.group():
  149.             text.delete(first, last)
  150.         if new:
  151.             text.insert(first, new)
  152.         text.undo_block_stop()
  153.         self.show_hit(first, text.index("insert"))
  154.         self.ok = 0
  155.         return 1
  156.  
  157.     def _expand(self, m, template):
  158.         # XXX This code depends on internals of the regular expression
  159.         # engine!  There's no standard API to do a substitution when you
  160.         # have already found the match.  One should be added.
  161.         # The solution here is designed to be backwards compatible
  162.         # with previous Python versions, e.g. 1.5.2.
  163.         # XXX This dynamic test should be done only once.
  164.         if getattr(re, "engine", "pre") == "pre":
  165.             return re.pcre_expand(m, template)
  166.         else: # sre
  167.             # XXX This import should be avoidable...
  168.             import sre_parse
  169.             # XXX This parses the template over and over...
  170.             ptemplate = sre_parse.parse_template(template, m.re)
  171.             return sre_parse.expand_template(ptemplate, m)
  172.  
  173.     def show_hit(self, first, last):
  174.         text = self.text
  175.         text.mark_set("insert", first)
  176.         text.tag_remove("sel", "1.0", "end")
  177.         text.tag_add("sel", first, last)
  178.         text.tag_remove("hit", "1.0", "end")
  179.         if first == last:
  180.             text.tag_add("hit", first)
  181.         else:
  182.             text.tag_add("hit", first, last)
  183.         text.see("insert")
  184.         text.update_idletasks()
  185.  
  186.     def close(self, event=None):
  187.         SearchDialogBase.close(self, event)
  188.         self.text.tag_remove("hit", "1.0", "end")
  189.