def __init__(self, window, pluginHelper, query): self._window = window self.pluginHelper = pluginHelper self.pluginHelper.registerSearcher(self) self.query = query self.files = {} self.numMatches = 0 self.numLines = 0 self.wasCancelled = False self.searchProcess = None self._collapseAll = False # if true, new nodes will be displayed collapsed self._createResultPanel() self._updateSummary() # searchSummary = "<span size=\"smaller\" foreground=\"#585858\">searching for </span><span size=\"smaller\"><i>%s</i></span><span size=\"smaller\" foreground=\"#585858\"> in </span><span size=\"smaller\"><i>%s</i></span>" % (query.text, query.directory) searchSummary = ( '<span size="smaller">' + _("searching for <i>%(keywords)s</i> in <i>%(folder)s</i>") % { "keywords": escapeMarkup(query.text), "folder": escapeMarkup(gobject.filename_display_name(query.directory)), } + "</span>" ) self.treeStore.append(None, [searchSummary, "", 0]) self.searchProcess = SearchProcess(query, self) self._updateSummary()
class FileSearcher: """ Gets a search query (and related info) and then handles everything related to that single file search: - creating a result window - starting grep (through SearchProcess) - displaying matches A FileSearcher object lives until its result panel is closed. """ def __init__(self, window, pluginHelper, query): self._window = window self.pluginHelper = pluginHelper self.pluginHelper.registerSearcher(self) self.query = query self.files = {} self.numMatches = 0 self.numLines = 0 self.wasCancelled = False self.searchProcess = None self._collapseAll = False # if true, new nodes will be displayed collapsed self._createResultPanel() self._updateSummary() # searchSummary = "<span size=\"smaller\" foreground=\"#585858\">searching for </span><span size=\"smaller\"><i>%s</i></span><span size=\"smaller\" foreground=\"#585858\"> in </span><span size=\"smaller\"><i>%s</i></span>" % (query.text, query.directory) searchSummary = ( '<span size="smaller">' + _("searching for <i>%(keywords)s</i> in <i>%(folder)s</i>") % { "keywords": escapeMarkup(query.text), "folder": escapeMarkup(gobject.filename_display_name(query.directory)), } + "</span>" ) self.treeStore.append(None, [searchSummary, "", 0]) self.searchProcess = SearchProcess(query, self) self._updateSummary() def handleResult(self, file, lineno, linetext): expandRow = False if not (self.files.has_key(file)): it = self._addResultFile(file) self.files[file] = it expandRow = True else: it = self.files[file] if self._collapseAll: expandRow = False self._addResultLine(it, lineno, linetext) if expandRow: path = self.treeStore.get_path(it) self.treeView.expand_row(path, False) self._updateSummary() def handleFinished(self): # print "(finished)" if not (self.tree): return self.searchProcess = None editBtn = self.tree.get_widget("btnModifyFileSearch") editBtn.hide() editBtn.set_label("gtk-edit") self._updateSummary() if self.wasCancelled: line = '<i><span foreground="red">' + _("(search was cancelled)") + "</span></i>" elif self.numMatches == 0: line = "<i>" + _("(no matching files found)") + "</i>" else: line = "<i>" + ngettext("found %d match", "found %d matches", self.numMatches) % self.numMatches line += ngettext(" (%d line)", " (%d lines)", self.numLines) % self.numLines line += ngettext(" in %d file", " in %d files", len(self.files)) % len(self.files) + "</i>" self.treeStore.append(None, [line, "", 0]) def _updateSummary(self): summary = ngettext("<b>%d</b> match", "<b>%d</b> matches", self.numMatches) % self.numMatches summary += "\n" + ngettext("in %d file", "in %d files", len(self.files)) % len(self.files) if self.searchProcess: summary += u"\u2026" # ellipsis character self.tree.get_widget("lblNumMatches").set_label(summary) def _createResultPanel(self): gladeFile = os.path.join(os.path.dirname(__file__), "file-search.glade") self.tree = gtk.glade.XML(gladeFile, "hbxFileSearchResult", domain=APP_NAME) self.tree.signal_autoconnect(self) resultContainer = self.tree.get_widget("hbxFileSearchResult") resultContainer.set_data("filesearcher", self) tabTitle = self.query.text if len(tabTitle) > 30: tabTitle = tabTitle[:30] + u"\u2026" # ellipsis character panel = self._window.get_bottom_panel() panel.add_item(resultContainer, tabTitle, "gtk-find") panel.activate_item(resultContainer) editBtn = self.tree.get_widget("btnModifyFileSearch") editBtn.set_label("gtk-stop") panel.set_property("visible", True) self.treeStore = gtk.TreeStore(str, str, int) self.treeView = self.tree.get_widget("tvFileSearchResult") self.treeView.set_model(self.treeStore) self.treeView.set_search_equal_func(resultSearchCb) tc = gtk.TreeViewColumn("File", gtk.CellRendererText(), markup=0) self.treeView.append_column(tc) def _addResultFile(self, filename): dispFilename = filename # remove leading search directory part if present: if dispFilename.startswith(self.query.directory): dispFilename = dispFilename[len(self.query.directory) :] dispFilename.lstrip("/") dispFilename = gobject.filename_display_name(dispFilename) (directory, file) = os.path.split(dispFilename) if directory: directory = os.path.normpath(directory) + "/" line = "%s<b>%s</b>" % (escapeMarkup(directory), escapeMarkup(file)) it = self.treeStore.append(None, [line, filename, 0]) return it def _addResultLine(self, it, lineno, linetext): addTruncationMarker = False if len(linetext) > 1000: linetext = linetext[:1000] addTruncationMarker = True if not (self.query.isRegExp): (linetext, numLineMatches) = escapeAndHighlight( linetext, self.query.text, self.query.caseSensitive, self.query.wholeWord ) self.numMatches += numLineMatches else: linetext = escapeMarkup(linetext) self.numMatches += 1 self.numLines += 1 if addTruncationMarker: linetext += '</span><span size="smaller"><i> [...]</i>' line = '<b>%d:</b> <span foreground="blue">%s</span>' % (lineno, linetext) self.treeStore.append(it, [line, None, lineno]) def on_row_activated(self, widget, path, col): selectedIter = self.treeStore.get_iter(path) parentIter = self.treeStore.iter_parent(selectedIter) lineno = 0 if parentIter == None: file = self.treeStore.get_value(selectedIter, 1) else: file = self.treeStore.get_value(parentIter, 1) lineno = self.treeStore.get_value(selectedIter, 2) if not (file): return uri = "file://%s" % urllib.quote(file) gedit.commands.load_uri(window=self._window, uri=uri, line_pos=lineno) if lineno > 0: # this is necessary for Gedit 2.17.4 and older (see gbo #401219) currDoc = self._window.get_active_document() currDoc.goto_line(lineno - 1) # -1 required to work around gbo #503665 currView = gedit.tab_get_from_document(currDoc).get_view() currView.scroll_to_cursor() # use an Idle handler so the document has time to load: gobject.idle_add(self.onDocumentOpenedCb, (lineno > 0)) def on_btnClose_clicked(self, button): self.destroy() def destroy(self): if self.searchProcess: self.searchProcess.destroy() self.searchProcess = None panel = self._window.get_bottom_panel() resultContainer = self.tree.get_widget("hbxFileSearchResult") resultContainer.set_data("filesearcher", None) panel.remove_item(resultContainer) self.treeStore = None self.treeView = None self._window = None self.files = {} self.tree = None self.pluginHelper.unregisterSearcher(self) def on_btnModify_clicked(self, button): if not (self.searchProcess): # edit search params pass else: # cancel search self.searchProcess.cancel() self.wasCancelled = True def on_tvFileSearchResult_button_press_event(self, treeview, event): if event.button == 3: path = treeview.get_path_at_pos(int(event.x), int(event.y)) if path != None: treeview.grab_focus() treeview.set_cursor(path[0], path[1], False) menu = gtk.Menu() mi = gtk.ImageMenuItem("gtk-copy") mi.connect_object("activate", FileSearcher.onCopyActivate, self, treeview, path[0]) mi.show() menu.append(mi) mi = gtk.SeparatorMenuItem() mi.show() menu.append(mi) mi = gtk.MenuItem(_("Expand All")) mi.connect_object("activate", FileSearcher.onExpandAllActivate, self, treeview) mi.show() menu.append(mi) mi = gtk.MenuItem(_("Collapse All")) mi.connect_object("activate", FileSearcher.onCollapseAllActivate, self, treeview) mi.show() menu.append(mi) menu.popup(None, None, None, event.button, event.time) return True else: return False def onCopyActivate(self, treeview, path): it = treeview.get_model().get_iter(path) markupText = treeview.get_model().get_value(it, 0) plainText = pango.parse_markup(markupText, u"\x00")[1] clipboard = gtk.clipboard_get() clipboard.set_text(plainText) clipboard.store() def onExpandAllActivate(self, treeview): self._collapseAll = False treeview.expand_all() def onCollapseAllActivate(self, treeview): self._collapseAll = True treeview.collapse_all() def onDocumentOpenedCb(self, doScroll): currDoc = self._window.get_active_document() if doScroll: # workaround to scroll to cursor position when opening file into window of "Unnamed Document": currView = gedit.tab_get_from_document(currDoc).get_view() currView.scroll_to_cursor() # highlight matches in opened document: flags = 0 if self.query.caseSensitive: flags |= 4 if self.query.wholeWord: flags |= 2 currDoc.set_search_text(self.query.text, flags) return False