forked from qt-creator/qt-creator
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:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user