Editor: Highlight Search results in scrollbar.

Change-Id: I999ddeeedbd6bdd7abebf75405d7e9281a1893df
Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
David Schulz
2015-06-04 10:43:34 +02:00
parent 92c902c70c
commit c82d287cbf
13 changed files with 753 additions and 58 deletions

View File

@@ -77,15 +77,18 @@
#include <coreplugin/infobar.h>
#include <coreplugin/manhattanstyle.h>
#include <coreplugin/find/basetextfind.h>
#include <coreplugin/find/highlightscrollbar.h>
#include <utils/linecolumnlabel.h>
#include <utils/fileutils.h>
#include <utils/dropsupport.h>
#include <utils/filesearch.h>
#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <utils/tooltip/tooltip.h>
#include <utils/uncommentselection.h>
#include <utils/theme/theme.h>
#include <QAbstractTextDocumentLayout>
#include <QApplication>
@@ -271,6 +274,7 @@ public:
void copyLineUpDown(bool up);
void saveCurrentCursorPositionForNavigation();
void updateHighlights();
void updateCurrentLineInScrollbar();
void updateCurrentLineHighlight();
void drawFoldingMarker(QPainter *painter, const QPalette &pal,
@@ -309,6 +313,19 @@ public:
void documentAboutToBeReloaded();
void documentReloadFinished(bool success);
void highlightSearchResultsSlot(const QString &txt, FindFlags findFlags);
void searchResultsReady(int beginIndex, int endIndex);
void searchFinished();
void setupScrollBar();
void highlightSearchResultsInScrollBar();
void scheduleUpdateHighlightScrollBar();
void updateHighlightScrollBarNow();
struct SearchResult {
int start;
int length;
};
void addSearchResultsToScrollBar(QVector<SearchResult> results);
void adjustScrollBarRanges();
void setFindScope(const QTextCursor &start, const QTextCursor &end, int, int);
void updateCursorPosition();
@@ -448,6 +465,12 @@ public:
QScopedPointer<AutoCompleter> m_autoCompleter;
CommentDefinition m_commentDefinition;
QFutureWatcher<FileSearchResultList> *m_searchWatcher;
QVector<SearchResult> m_searchResults;
QTimer m_scrollBarUpdateTimer;
HighlightScrollBar *m_highlightScrollBar;
bool m_scrollBarUpdateScheduled;
};
TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
@@ -499,7 +522,11 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
m_markDragging(false),
m_clipboardAssistProvider(new ClipboardAssistProvider),
m_isMissingSyntaxDefinition(false),
m_autoCompleter(new AutoCompleter)
m_autoCompleter(new AutoCompleter),
m_searchWatcher(0),
m_scrollBarUpdateTimer(0),
m_highlightScrollBar(0),
m_scrollBarUpdateScheduled(false)
{
Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
BaseTextFind *baseTextFind = new BaseTextFind(q);
@@ -606,6 +633,29 @@ void TextEditorWidget::setTextDocument(const QSharedPointer<TextDocument> &doc)
d->ctor(doc);
}
void TextEditorWidgetPrivate::setupScrollBar()
{
if (m_displaySettings.m_scrollBarHighlights) {
if (m_highlightScrollBar)
return;
m_highlightScrollBar = new HighlightScrollBar(Qt::Vertical, q);
m_highlightScrollBar->setColor(Constants::SCROLL_BAR_SEARCH_RESULT,
Theme::TextEditor_SearchResult_ScrollBarColor);
m_highlightScrollBar->setColor(Constants::SCROLL_BAR_CURRENT_LINE,
Theme::TextEditor_CurrentLine_ScrollBarColor);
m_highlightScrollBar->setPriority(
Constants::SCROLL_BAR_SEARCH_RESULT, HighlightScrollBar::HighPriority);
m_highlightScrollBar->setPriority(
Constants::SCROLL_BAR_CURRENT_LINE, HighlightScrollBar::HighestPriority);
q->setVerticalScrollBar(m_highlightScrollBar);
highlightSearchResultsInScrollBar();
scheduleUpdateHighlightScrollBar();
} else if (m_highlightScrollBar) {
q->setVerticalScrollBar(new QScrollBar(Qt::Vertical, q));
m_highlightScrollBar = 0;
}
}
void TextEditorWidgetPrivate::ctor(const QSharedPointer<TextDocument> &doc)
{
q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
@@ -668,6 +718,10 @@ void TextEditorWidgetPrivate::ctor(const QSharedPointer<TextDocument> &doc)
QObject::connect(&m_highlightBlocksTimer, &QTimer::timeout,
this, &TextEditorWidgetPrivate::_q_highlightBlocks);
m_scrollBarUpdateTimer.setSingleShot(true);
QObject::connect(&m_scrollBarUpdateTimer, &QTimer::timeout,
this, &TextEditorWidgetPrivate::highlightSearchResultsInScrollBar);
m_animator = 0;
slotUpdateExtraAreaWidth();
@@ -1073,6 +1127,7 @@ void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemove
q->verticalScrollBar()->setValue(q->verticalScrollBar()->value() + newBlockCount - m_blockCount);
}
m_blockCount = newBlockCount;
m_scrollBarUpdateTimer.start(500);
}
void TextEditorWidgetPrivate::slotSelectionChanged()
@@ -2568,6 +2623,9 @@ void TextEditorWidgetPrivate::documentAboutToBeReloaded()
m_snippetOverlay->clear();
m_searchResultOverlay->clear();
m_refactorOverlay->clear();
// clear search results
m_searchResults.clear();
}
void TextEditorWidgetPrivate::documentReloadFinished(bool success)
@@ -2873,6 +2931,15 @@ void TextEditorWidgetPrivate::setupDocumentSignals()
QObject::connect(q, &TextEditorWidget::requestBlockUpdate,
documentLayout, &QPlainTextDocumentLayout::updateBlock);
QObject::connect(documentLayout, &TextDocumentLayout::updateExtraArea,
this, &TextEditorWidgetPrivate::scheduleUpdateHighlightScrollBar);
QObject::connect(documentLayout, &QAbstractTextDocumentLayout::documentSizeChanged,
this, &TextEditorWidgetPrivate::scheduleUpdateHighlightScrollBar);
QObject::connect(documentLayout, &QAbstractTextDocumentLayout::update,
this, &TextEditorWidgetPrivate::scheduleUpdateHighlightScrollBar);
QObject::connect(doc, &QTextDocument::contentsChange,
this, &TextEditorWidgetPrivate::editorContentsChange);
@@ -3050,6 +3117,8 @@ void TextEditorWidget::resizeEvent(QResizeEvent *e)
d->m_extraArea->setGeometry(
QStyle::visualRect(layoutDirection(), cr,
QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
d->adjustScrollBarRanges();
d->updateCurrentLineInScrollbar();
}
QRect TextEditorWidgetPrivate::foldBox()
@@ -4584,6 +4653,7 @@ void TextEditorWidgetPrivate::updateCurrentLineHighlight()
sel.cursor.clearSelection();
extraSelections.append(sel);
}
updateCurrentLineInScrollbar();
q->setExtraSelections(TextEditorWidget::CurrentLineSelection, extraSelections);
@@ -4649,6 +4719,20 @@ void TextEditorWidgetPrivate::updateHighlights()
}
}
void TextEditorWidgetPrivate::updateCurrentLineInScrollbar()
{
if (m_highlightCurrentLine && m_highlightScrollBar) {
m_highlightScrollBar->removeHighlights(Constants::SCROLL_BAR_CURRENT_LINE);
if (m_highlightScrollBar->maximum() > 0) {
const QTextCursor &tc = q->textCursor();
const int lineNumberInBlock =
tc.block().layout()->lineForTextPosition(tc.positionInBlock()).lineNumber();
m_highlightScrollBar->addHighlight(Constants::SCROLL_BAR_CURRENT_LINE,
q->textCursor().block().firstLineNumber() + lineNumberInBlock);
}
}
}
void TextEditorWidgetPrivate::slotUpdateBlockNotify(const QTextBlock &block)
{
static bool blockRecursion = false;
@@ -5466,6 +5550,158 @@ void TextEditorWidgetPrivate::highlightSearchResultsSlot(const QString &txt, Fin
m_findFlags = findFlags;
m_delayedUpdateTimer.start(50);
if (m_highlightScrollBar)
m_scrollBarUpdateTimer.start(50);
}
void TextEditorWidgetPrivate::searchResultsReady(int beginIndex, int endIndex)
{
QVector<SearchResult> results;
for (int index = beginIndex; index < endIndex; ++index) {
foreach (Utils::FileSearchResult result, m_searchWatcher->resultAt(index)) {
const QTextBlock &block = q->document()->findBlockByNumber(result.lineNumber - 1);
const int matchStart = block.position() + result.matchStart;
if (!q->inFindScope(matchStart, matchStart + result.matchLength))
continue;
results << SearchResult{matchStart, result.matchLength};
}
}
m_searchResults << results;
addSearchResultsToScrollBar(results);
}
void TextEditorWidgetPrivate::searchFinished()
{
delete m_searchWatcher;
m_searchWatcher = 0;
}
void TextEditorWidgetPrivate::adjustScrollBarRanges()
{
if (!m_highlightScrollBar)
return;
const float lineSpacing = QFontMetricsF(q->font()).lineSpacing();
if (lineSpacing == 0)
return;
const float offset = q->contentOffset().y();
m_highlightScrollBar->setVisibleRange((q->viewport()->rect().height() - offset) / lineSpacing);
m_highlightScrollBar->setRangeOffset(offset / lineSpacing);
}
void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar()
{
if (!m_highlightScrollBar)
return;
m_highlightScrollBar->removeHighlights(Constants::SCROLL_BAR_SEARCH_RESULT);
m_searchResults.clear();
if (m_searchWatcher) {
m_searchWatcher->disconnect();
m_searchWatcher->cancel();
m_searchWatcher->deleteLater();
m_searchWatcher = 0;
}
const QString &txt = m_searchExpr.pattern();
if (txt.isEmpty())
return;
adjustScrollBarRanges();
m_searchWatcher = new QFutureWatcher<FileSearchResultList>();
connect(m_searchWatcher, &QFutureWatcher<Utils::FileSearchResultList>::resultsReadyAt,
this, &TextEditorWidgetPrivate::searchResultsReady);
connect(m_searchWatcher, &QFutureWatcher<Utils::FileSearchResultList>::finished,
this, &TextEditorWidgetPrivate::searchFinished);
m_searchWatcher->setPendingResultsLimit(10);
const QTextDocument::FindFlags findFlags = textDocumentFlagsForFindFlags(m_findFlags);
const QString &fileName = m_document->filePath().toString();
FileListIterator *it =
new FileListIterator( { fileName } , { const_cast<QTextCodec *>(m_document->codec()) } );
QMap<QString, QString> fileToContentsMap;
fileToContentsMap[fileName] = m_document->plainText();
if (m_findFlags & FindRegularExpression)
m_searchWatcher->setFuture(findInFilesRegExp(txt, it, findFlags, fileToContentsMap));
else
m_searchWatcher->setFuture(findInFiles(txt, it, findFlags, fileToContentsMap));
}
void TextEditorWidgetPrivate::scheduleUpdateHighlightScrollBar()
{
if (m_scrollBarUpdateScheduled)
return;
m_scrollBarUpdateScheduled = true;
QTimer::singleShot(0, this, &TextEditorWidgetPrivate::updateHighlightScrollBarNow);
}
HighlightScrollBar::Priority textMarkPrioToScrollBarPrio(const TextMark::Priority &prio)
{
switch (prio) {
case TextMark::LowPriority:
return HighlightScrollBar::LowPriority;
case TextMark::NormalPriority:
return HighlightScrollBar::NormalPriority;
case TextMark::HighPriority:
return HighlightScrollBar::HighPriority;
default:
return HighlightScrollBar::NormalPriority;
}
}
void TextEditorWidgetPrivate::addSearchResultsToScrollBar(QVector<SearchResult> results)
{
QSet<int> searchResults;
foreach (SearchResult result, results) {
const QTextBlock &block = q->document()->findBlock(result.start);
if (block.isValid() && block.isVisible()) {
const int firstLine = block.layout()->lineForTextPosition(result.start - block.position()).lineNumber();
const int lastLine = block.layout()->lineForTextPosition(result.start - block.position() + result.length).lineNumber();
for (int line = firstLine; line <= lastLine; ++line)
searchResults << block.firstLineNumber() + line;
}
}
if (m_highlightScrollBar)
m_highlightScrollBar->addHighlights(Constants::SCROLL_BAR_SEARCH_RESULT, searchResults);
}
void TextEditorWidgetPrivate::updateHighlightScrollBarNow()
{
typedef QSet<int> IntSet;
m_scrollBarUpdateScheduled = false;
if (!m_highlightScrollBar)
return;
m_highlightScrollBar->removeAllHighlights();
updateCurrentLineInScrollbar();
// update search results
addSearchResultsToScrollBar(m_searchResults);
// update text marks
QHash<Id, IntSet> marks;
foreach (TextMark *mark, m_document->marks()) {
Id category = mark->category();
if (!mark->isVisible() || !TextMark::categoryHasColor(category))
continue;
m_highlightScrollBar->setPriority(category, textMarkPrioToScrollBarPrio(mark->priority()));
const QTextBlock &block = q->document()->findBlockByNumber(mark->lineNumber() - 1);
if (block.isVisible())
marks[category] << block.firstLineNumber();
}
QHashIterator<Id, IntSet> it(marks);
while (it.hasNext()) {
it.next();
m_highlightScrollBar->setColor(it.key(), TextMark::categoryColor(it.key()));
m_highlightScrollBar->addHighlights(it.key(), it.value());
}
}
int TextEditorWidget::verticalBlockSelectionFirstColumn() const
@@ -5510,6 +5746,7 @@ void TextEditorWidgetPrivate::setFindScope(const QTextCursor &start, const QText
m_findScopeVerticalBlockSelectionFirstColumn = verticalBlockSelectionFirstColumn;
m_findScopeVerticalBlockSelectionLastColumn = verticalBlockSelectionLastColumn;
q->viewport()->update();
highlightSearchResultsInScrollBar();
}
}
@@ -6204,6 +6441,7 @@ void TextEditorWidget::setDisplaySettings(const DisplaySettings &ds)
d->updateCodeFoldingVisible();
d->updateHighlights();
d->setupScrollBar();
viewport()->update();
extraArea()->update();
}