From: <wal...@us...> - 2009-01-13 13:50:21
|
Revision: 9646 http://translate.svn.sourceforge.net/translate/?rev=9646&view=rev Author: walter_l Date: 2009-01-13 13:50:08 +0000 (Tue, 13 Jan 2009) Log Message: ----------- Now that the actual searching code has been moved to translate.tools.pogrep, Virtaal now has to use it from there and not its own. This fixes bug 659. Modified Paths: -------------- src/trunk/virtaal/virtaal/modes/searchmode.py Modified: src/trunk/virtaal/virtaal/modes/searchmode.py =================================================================== --- src/trunk/virtaal/virtaal/modes/searchmode.py 2009-01-13 13:49:30 UTC (rev 9645) +++ src/trunk/virtaal/virtaal/modes/searchmode.py 2009-01-13 13:50:08 UTC (rev 9646) @@ -23,110 +23,18 @@ import gtk.gdk import logging import re +from translate.tools.pogrep import GrepFilter from virtaal.controllers import Cursor from basemode import BaseMode -class SearchMatch(object): - """Just a small data structure that represents a search match.""" - - # INITIALIZERS # - def __init__(self, unit, part='target', part_n=0, start=0, end=0): - self.unit = unit - self.part = part - self.part_n = part_n - self.start = start - self.end = end - - # ACCESSORS # - def get_getter(self): - if self.part == 'target': - def getter(): - return self.unit.target.strings[self.part_n] - return getter - elif self.part == 'source': - def getter(): - return self.unit.source.strings[self.part_n] - return getter - elif self.part == 'notes': - def getter(): - return self.unit.getnotes()[self.part_n] - return getter - elif self.part == 'locations': - def getter(): - return self.unit.getlocations()[self.part_n] - return getter - - def get_setter(self): - if self.part == 'target': - def setter(value): - strings = self.unit.target.strings - strings[self.part_n] = value - self.unit.target = strings - return setter - - # METHODS # - def select(self, main_controller): - """Select this match in the GUI.""" - main_controller.select_unit(self.unit) - view = main_controller.unit_controller.view - - # Wait for SearchMode to finish with its highlighting and stuff, and then we do... - if self.part == 'target': - def select_match_text(): - target = view.targets[self.part_n] - target.grab_focus() - buff = target.get_buffer() - start_iter = buff.get_iter_at_offset(self.start) - end_iter = buff.get_iter_at_offset(self.end) - buff.select_range(end_iter, start_iter) - return False - elif self.part == 'source': - def select_match_text(): - source = view.sources[self.part_n] - source.grab_focus() - buff = source.get_buffer() - start_iter = buff.get_iter_at_offset(self.start) - end_iter = buff.get_iter_at_offset(self.end) - buff.select_range(end_iter, start_iter) - return False - # TODO: Implement for 'notes' and 'locations' parts - gobject.idle_add(select_match_text) - - def replace(self, replace_str, main_controller=None): - unit_controller = main_controller.unit_controller - # Using unit_controller directly is a hack to make sure that the replacement changes are immediately displayed. - if self.part != 'target': - return - strings = self.unit.target.strings - string_n = strings[self.part_n] - if unit_controller is None: - strings[self.part_n] = string_n[:self.start] + replace_str + string_n[self.end:] - self.unit.target = strings - else: - main_controller.select_unit(self.unit) - unit_controller.set_unit_target(self.part_n, string_n[:self.start] + replace_str + string_n[self.end:]) - - # SPECIAL METHODS # - def __str__(self): - start, end = self.start, self.end - if start < 3: - start = 3 - if end > len(self.get_getter()()) - 3: - end = len(self.get_getter()()) - 3 - matchpart = self.get_getter()()[start-2:end+2] - return '<SearchMatch "%s" part=%s[%d] start=%d end=%d>' % (matchpart, self.part, self.part_n, self.start, self.end) - - def __repr__(self): - return str(self) - - class SearchMode(BaseMode): """Search mode - Includes only units matching the given search term.""" display_name = _("Search") + name = 'Search' widgets = [] MAX_RESULTS = 100000 @@ -143,7 +51,6 @@ self._setup_key_bindings() self.matches = [] - self.re_search = None self.select_first_match = True self._search_timeout = 0 self._unit_modified_id = 0 @@ -191,91 +98,6 @@ # METHODS # - def get_matches(self, units): - if not self.ent_search.get_text(): - return [] - - searchstring = self.ent_search.get_text().decode('utf-8') - searchparts = ('source', 'target') - ignorecase = not self.chk_casesensitive.get_active() - useregexp = self.chk_regex.get_active() - flags = re.LOCALE | re.MULTILINE | re.UNICODE - - if ignorecase: - flags |= re.IGNORECASE - if not useregexp: - searchstring = re.escape(searchstring) - self.re_search = re.compile(u'(%s)' % (searchstring), flags) - - matches = [] - indexes = [] - - for index, unit in enumerate(units): - unit_matches = False - - if 'target' in searchparts: - part = 'target' - part_n = 0 - if unit.hasplural(): - targets = unit.target.strings - else: - targets = [unit.target] - for target in targets: - for matchobj in self.re_search.finditer(target): - matches.append( - SearchMatch(unit, part=part, part_n=part_n, start=matchobj.start(), end=matchobj.end()) - ) - unit_matches = True - part_n += 1 - - if 'source' in searchparts: - part = 'source' - part_n = 0 - if unit.hasplural(): - sources = unit.source.strings - else: - sources = [unit.source] - for source in sources: - for matchobj in self.re_search.finditer(source): - matches.append( - SearchMatch(unit, part=part, part_n=part_n, start=matchobj.start(), end=matchobj.end()) - ) - unit_matches = True - part_n += 1 - - if 'notes' in searchparts: - part = 'notes' - part_n = 0 - for note in unit.getnotes(): - for matchobj in self.re_search.finditer(note): - matches.append( - SearchMatch(unit, part=part, part_n=part_n, start=matchobj.start(), end=matchobj.end()) - ) - unit_matches = True - part_n += 1 - - if 'locations' in searchparts: - part = 'locations' - part_n = 0 - for loc in unit.getlocations(): - for matchobj in self.re_search.finditer(loc): - matches.append( - SearchMatch(unit, part=part, part_n=part_n, start=matchobj.start(), end=matchobj.end()) - ) - unit_matches = True - part_n += 1 - - # A search for a single letter or an all-inclusive regular - # expression could give enough results to cause performance - # problems. The answer is probably not very useful at this scale. - if len(matches) > self.MAX_RESULTS: - raise Exception("Too many matches for search") - - if unit_matches: - indexes.append(index) - - return matches, indexes - def selected(self): # XXX: Assumption: This method is called when a new file is loaded and that is # why we keep a reference to the store's cursor. @@ -297,9 +119,59 @@ # FIXME: The following line is a VERY UGLY HACK, but at least it works. gobject.timeout_add(100, grab_focus) + def select_match(self, match): + """Select the specified match in the GUI.""" + main_controller = self.controller.main_controller + main_controller.select_unit(match.unit) + view = main_controller.unit_controller.view + + # Wait for SearchMode to finish with its highlighting and stuff, and then we do... + if match.part == 'target': + def select_match_text(): + target = view.targets[match.part_n] + target.grab_focus() + buff = target.get_buffer() + start_iter = buff.get_iter_at_offset(match.start) + end_iter = buff.get_iter_at_offset(match.end) + buff.select_range(end_iter, start_iter) + return False + elif match.part == 'source': + def select_match_text(): + source = view.sources[match.part_n] + source.grab_focus() + buff = source.get_buffer() + start_iter = buff.get_iter_at_offset(match.start) + end_iter = buff.get_iter_at_offset(match.end) + buff.select_range(end_iter, start_iter) + return False + # TODO: Implement for 'notes' and 'locations' parts + gobject.idle_add(select_match_text) + + def replace_match(self, match, replace_str): + main_controller = self.controller.main_controller + unit_controller = main_controller.unit_controller + # Using unit_controller directly is a hack to make sure that the replacement changes are immediately displayed. + if match.part != 'target': + return + strings = match.unit.target.strings + string_n = strings[match.part_n] + if unit_controller is None: + strings[match.part_n] = string_n[:match.start] + replace_str + string_n[match.end:] + match.unit.target = strings + else: + main_controller.select_unit(match.unit) + unit_controller.set_unit_target(match.part_n, string_n[:match.start] + replace_str + string_n[match.end:]) + def update_search(self): + self.filter = GrepFilter( + searchstring=unicode(self.ent_search.get_text()), + searchparts=('source', 'target'), + ignorecase=not self.chk_casesensitive.get_active(), + useregexp=self.chk_regex.get_active(), + max_matches=self.MAX_RESULTS + ) store_units = self.storecursor.model.get_units() - self.matches, indexes = self.get_matches(store_units) + self.matches, indexes = self.filter.getmatches(store_units) self.matchcursor = Cursor(self.matches, range(len(self.matches))) logging.debug('Search text: %s (%d matches)' % (self.ent_search.get_text(), len(indexes))) @@ -320,7 +192,7 @@ else: self.ent_search.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#f66')) self.ent_search.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff')) - self.re_search = None + self.filter.re_search = None # Act like the "Default" mode... self.storecursor.indices = self.storecursor.model.stats['total'] self._highlight_matches() @@ -366,7 +238,7 @@ def _highlight_matches(self): self._unhighlight_previous_matches() - if self.re_search is None: + if self.filter.re_search is None: return unitview = self.controller.main_controller.unit_controller.view @@ -386,8 +258,11 @@ pass select_iters = [] - for match in self.re_search.finditer(buffstr): - start_iter, end_iter = buff.get_iter_at_offset(match.start()), buff.get_iter_at_offset(match.end()) + for match in [m for m in self.matches if m.unit is unitview.unit]: + if (textview in unitview.sources and not match.part == 'source') or \ + (textview in unitview.targets and not match.part == 'target'): + continue + start_iter, end_iter = buff.get_iter_at_offset(match.start), buff.get_iter_at_offset(match.end) buff.apply_tag_by_name('highlight', start_iter, end_iter) if textview in unitview.targets and not select_iters and self.select_first_match: @@ -415,12 +290,12 @@ return self.matchcursor.move(offset) - self.matches[self.matchcursor.index].select(self.controller.main_controller) + self.select_match(self.matches[self.matchcursor.index]) def _replace_all(self): self.controller.main_controller.undo_controller.record_start() for match in self.matches: - match.replace(self.ent_replace.get_text(), self.controller.main_controller) + self.replace_match(match, self.ent_replace.get_text()) self.controller.main_controller.undo_controller.record_stop() def _unhighlight_previous_matches(self): @@ -458,7 +333,7 @@ # Find matches in the current unit. unit_matches = [match for match in self.matches if match.unit is current_unit and match.part == 'target'] if len(unit_matches) > 0: - unit_matches[0].replace(self.ent_replace.get_text(), self.controller.main_controller) + self.replace_match(unit_matches[0], self.ent_replace.get_text()) self.controller.main_controller.undo_controller.undo_stack.pop() self.controller.main_controller.undo_controller.undo_stack.undo_stack.pop() self.matches.remove(unit_matches[0]) @@ -490,7 +365,7 @@ def _on_unit_modified(self, unit_controller, current_unit): unit_matches = self._get_matches_for_unit(current_unit) for match in unit_matches: - if not self.re_search.match(match.get_getter()()[match.start:match.end]): + if not self.filter.re_search.match(match.get_getter()()[match.start:match.end]): logging.debug('Match to remove: %s' % (match)) self.matches.remove(match) self.matchcursor.indices = range(len(self.matches)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |