Example #1
0
    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()
Example #2
0
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