'Search for query, also searching the headers. Matches in headers
are not highlighted as managing the highlight is too much of a pain.'

def search(self, query, reverse=False):

    if (not query.strip()):
        return
    c = self.textCursor()
    lnum = c.block().blockNumber()
    cpos = c.positionInBlock()
    headers = dict(self.headers)
    if (lnum in headers):
        cpos = self.search_header_pos
    lines = unicode(self.toPlainText()).splitlines()
    for (hn, text) in self.headers:
        lines[hn] = text
    (prefix, postfix) = (lines[lnum][:cpos], lines[lnum][cpos:])
    (before, after) = (enumerate(lines[0:lnum]), ((((lnum + 1) + i), x) for (i, x) in enumerate(lines[(lnum + 1):])))
    if reverse:
        sl = chain([(lnum, prefix)], reversed(tuple(before)), reversed(tuple(after)), [(lnum, postfix)])
    else:
        sl = chain([(lnum, postfix)], after, before, [(lnum, prefix)])
    flags = (regex.REVERSE if reverse else 0)
    pat = regex.compile(regex.escape(query, special_only=True), flags=((regex.UNICODE | regex.IGNORECASE) | flags))
    for (num, text) in sl:
        try:
            m = next(pat.finditer(text))
        except StopIteration:
            continue
        (start, end) = m.span()
        length = (end - start)
        if (text is postfix):
            start += cpos
        c = QTextCursor(self.document().findBlockByNumber(num))
        c.setPosition((c.position() + start))
        if (num in headers):
            self.search_header_pos = (start + length)
        else:
            c.setPosition((c.position() + length), c.KeepAnchor)
            self.search_header_pos = 0
        if reverse:
            (pos, anchor) = (c.position(), c.anchor())
            (c.setPosition(pos), c.setPosition(anchor, c.KeepAnchor))
        self.setTextCursor(c)
        self.centerCursor()
        self.scrolled.emit()
        break
    else:
        info_dialog(self, _(u'No    matches    found'), _((u'No    matches    found    for    query:    %s' % query)), show=True)
