Commit 990da15c authored by Jarek Kobus's avatar Jarek Kobus

Refactor HighlightScrollBar

Rename it into HighlightScrollBarController.
Don't derive it anymore from QScrollBar.
Make it based on QObject and decorate
the existing instance of QAbstractScrollArea as needed.

Fix the highlight of the shared scrollbar of the SideBySideDiffEditor.
Both left and right diff editors have their own
HighlightScrollBarController and their own separate overlays, but both
overlays are created as children of the same right editor instance.

Synchronize also the cursor between left and right editors.
Make highlight current line working.

Make the overlay transparent for mouse events - this fixes
issues on macOS when scolling over invisible scrollbar.

Change-Id: Iab05c360173e09d8748658c59785da86438a7189
Reviewed-by: David Schulz's avatarDavid Schulz <david.schulz@qt.io>
parent 11d00296
......@@ -223,8 +223,8 @@ Project {
"findtoolwindow.cpp",
"findtoolwindow.h",
"findwidget.ui",
"highlightscrollbar.cpp",
"highlightscrollbar.h",
"highlightscrollbarcontroller.cpp",
"highlightscrollbarcontroller.h",
"ifindfilter.cpp",
"ifindfilter.h",
"ifindsupport.cpp",
......
......@@ -4,6 +4,7 @@ HEADERS += \
$$PWD/findplugin.h \
$$PWD/findtoolbar.h \
$$PWD/findtoolwindow.h \
$$PWD/highlightscrollbarcontroller.h \
$$PWD/ifindfilter.h \
$$PWD/ifindsupport.h \
$$PWD/itemviewfind.h \
......@@ -16,7 +17,6 @@ HEADERS += \
$$PWD/searchresultwidget.h \
$$PWD/searchresultwindow.h \
$$PWD/textfindconstants.h \
$$PWD/highlightscrollbar.h \
$$PWD/searchresultitem.h
SOURCES += \
......@@ -25,6 +25,7 @@ SOURCES += \
$$PWD/findplugin.cpp \
$$PWD/findtoolbar.cpp \
$$PWD/findtoolwindow.cpp \
$$PWD/highlightscrollbarcontroller.cpp \
$$PWD/ifindfilter.cpp \
$$PWD/ifindsupport.cpp \
$$PWD/itemviewfind.cpp \
......@@ -33,8 +34,7 @@ SOURCES += \
$$PWD/searchresulttreemodel.cpp \
$$PWD/searchresulttreeview.cpp \
$$PWD/searchresultwidget.cpp \
$$PWD/searchresultwindow.cpp \
$$PWD/highlightscrollbar.cpp
$$PWD/searchresultwindow.cpp
FORMS += \
......
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
......@@ -25,14 +25,19 @@
#pragma once
#include <QMap>
#include <QScrollBar>
#include <QSet>
#include <QHash>
#include <QPointer>
#include <QVector>
#include <coreplugin/core_global.h>
#include <coreplugin/id.h>
#include <utils/theme/theme.h>
QT_BEGIN_NAMESPACE
class QAbstractScrollArea;
class QScrollBar;
QT_END_NAMESPACE
namespace Core {
struct CORE_EXPORT Highlight
......@@ -56,38 +61,34 @@ struct CORE_EXPORT Highlight
class HighlightScrollBarOverlay;
class CORE_EXPORT HighlightScrollBar : public QScrollBar
class CORE_EXPORT HighlightScrollBarController
{
Q_OBJECT
public:
HighlightScrollBar(Qt::Orientation orientation, QWidget *parent = 0);
~HighlightScrollBar() override;
HighlightScrollBarController() = default;
~HighlightScrollBarController();
QScrollBar *scrollBar() const;
QAbstractScrollArea *scrollArea() const;
void setScrollArea(QAbstractScrollArea *scrollArea);
float visibleRange() const;
void setVisibleRange(float visibleRange);
float rangeOffset() const;
void setRangeOffset(float offset);
QHash<Id, QVector<Highlight>> highlights() const;
void addHighlight(Highlight highlight);
void removeHighlights(Id id);
void removeAllHighlights();
bool eventFilter(QObject *, QEvent *event) override;
protected:
void moveEvent(QMoveEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void showEvent(QShowEvent *event) override;
void hideEvent(QHideEvent *event) override;
void changeEvent(QEvent *even) override;
private:
QRect overlayRect();
void overlayDestroyed();
QWidget *m_widget;
HighlightScrollBarOverlay *m_overlay;
friend class HighlightScrollBarOverlay;
QHash<Id, QVector<Highlight> > m_highlights;
float m_visibleRange = 0.0;
float m_rangeOffset = 0.0;
QAbstractScrollArea *m_scrollArea = nullptr;
QPointer<HighlightScrollBarOverlay> m_overlay;
};
} // namespace Core
......@@ -108,7 +108,6 @@ DescriptionEditorWidget::DescriptionEditorWidget(QWidget *parent)
DisplaySettings settings = displaySettings();
settings.m_textWrapping = false;
settings.m_displayLineNumbers = false;
settings.m_highlightCurrentLine = false;
settings.m_displayFoldingMarkers = false;
settings.m_markTextChanges = false;
settings.m_highlightBlocks = false;
......@@ -143,6 +142,8 @@ void DescriptionEditorWidget::setDisplaySettings(const DisplaySettings &ds)
{
DisplaySettings settings = displaySettings();
settings.m_visualizeWhitespace = ds.m_visualizeWhitespace;
settings.m_scrollBarHighlights = ds.m_scrollBarHighlights;
settings.m_highlightCurrentLine = ds.m_highlightCurrentLine;
TextEditorWidget::setDisplaySettings(settings);
}
......
......@@ -42,6 +42,7 @@
#include <texteditor/displaysettings.h>
#include <coreplugin/icore.h>
#include <coreplugin/find/highlightscrollbarcontroller.h>
#include <coreplugin/minisplitter.h>
#include <utils/tooltip/tooltip.h>
......@@ -98,6 +99,8 @@ signals:
int diffFileIndex,
int chunkIndex);
void foldChanged(int blockNumber, bool folded);
void gotDisplaySettings();
void gotFocus();
protected:
int extraAreaWidth(int *markWidthPtr = nullptr) const override {
......@@ -124,6 +127,7 @@ protected:
const QTextBlock &block,
QPointF offset,
const QRect &clip) override;
void focusInEvent(QFocusEvent *e) override;
private:
void paintSeparator(QPainter &painter, QColor &color, const QString &text,
......@@ -158,7 +162,6 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent)
DisplaySettings settings = displaySettings();
settings.m_textWrapping = false;
settings.m_displayLineNumbers = true;
settings.m_highlightCurrentLine = false;
settings.m_markTextChanges = false;
settings.m_highlightBlocks = false;
SelectableTextEditorWidget::setDisplaySettings(settings);
......@@ -217,7 +220,10 @@ void SideDiffEditorWidget::setDisplaySettings(const DisplaySettings &ds)
DisplaySettings settings = displaySettings();
settings.m_visualizeWhitespace = ds.m_visualizeWhitespace;
settings.m_displayFoldingMarkers = ds.m_displayFoldingMarkers;
settings.m_scrollBarHighlights = ds.m_scrollBarHighlights;
settings.m_highlightCurrentLine = ds.m_highlightCurrentLine;
SelectableTextEditorWidget::setDisplaySettings(settings);
emit gotDisplaySettings();
}
void SideDiffEditorWidget::applyFontSettings()
......@@ -604,6 +610,12 @@ void SideDiffEditorWidget::drawCollapsedBlockPopup(QPainter &painter,
m_drawCollapsedClip = clip;
}
void SideDiffEditorWidget::focusInEvent(QFocusEvent *e)
{
SelectableTextEditorWidget::focusInEvent(e);
emit gotFocus();
}
//////////////////
SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
......@@ -613,9 +625,6 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
m_leftEditor = new SideDiffEditorWidget(this);
m_leftEditor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_leftEditor->setReadOnly(true);
connect(TextEditorSettings::instance(), &TextEditorSettings::displaySettingsChanged,
m_leftEditor, &SideDiffEditorWidget::setDisplaySettings);
m_leftEditor->setDisplaySettings(TextEditorSettings::displaySettings());
m_leftEditor->setCodeStyle(TextEditorSettings::codeStyle());
connect(m_leftEditor, &SideDiffEditorWidget::jumpToOriginalFileRequested,
this, &SideBySideDiffEditorWidget::slotLeftJumpToOriginalFileRequested);
......@@ -625,9 +634,6 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
m_rightEditor = new SideDiffEditorWidget(this);
m_rightEditor->setReadOnly(true);
connect(TextEditorSettings::instance(), &TextEditorSettings::displaySettingsChanged,
m_rightEditor, &SideDiffEditorWidget::setDisplaySettings);
m_rightEditor->setDisplaySettings(TextEditorSettings::displaySettings());
m_rightEditor->setCodeStyle(TextEditorSettings::codeStyle());
connect(m_rightEditor, &SideDiffEditorWidget::jumpToOriginalFileRequested,
this, &SideBySideDiffEditorWidget::slotRightJumpToOriginalFileRequested);
......@@ -635,6 +641,44 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
this, &SideBySideDiffEditorWidget::slotRightContextMenuRequested,
Qt::DirectConnection);
auto setupHighlightController = [this]() {
HighlightScrollBarController *highlightController = m_leftEditor->highlightScrollBarController();
if (highlightController)
highlightController->setScrollArea(m_rightEditor);
};
setupHighlightController();
connect(m_leftEditor, &SideDiffEditorWidget::gotDisplaySettings, setupHighlightController);
m_rightEditor->verticalScrollBar()->setFocusProxy(m_leftEditor);
connect(m_leftEditor, &SideDiffEditorWidget::gotFocus, [this]() {
if (m_rightEditor->verticalScrollBar()->focusProxy() == m_leftEditor)
return; // We already did it before.
// Hack #1. If the left editor got a focus last time
// we don't want to focus right editor when clicking the right
// scrollbar.
m_rightEditor->verticalScrollBar()->setFocusProxy(m_leftEditor);
// Hack #2. If the focus is currently not on the scrollbar's proxy
// and we click on the scrollbar, the focus will go to the parent
// of the scrollbar. In order to give the focus to the proxy
// we need to set a click focus policy on the scrollbar.
// See QApplicationPrivate::giveFocusAccordingToFocusPolicy().
m_rightEditor->verticalScrollBar()->setFocusPolicy(Qt::ClickFocus);
// Hack #3. Setting the focus policy is not orthogonal to setting
// the focus proxy and unfortuantely it changes the policy of the proxy
// too. We bring back the original policy to keep tab focus working.
m_leftEditor->setFocusPolicy(Qt::StrongFocus);
});
connect(m_rightEditor, &SideDiffEditorWidget::gotFocus, [this]() {
// Unhack #1.
m_rightEditor->verticalScrollBar()->setFocusProxy(nullptr);
// Unhack #2.
m_rightEditor->verticalScrollBar()->setFocusPolicy(Qt::NoFocus);
});
connect(TextEditorSettings::instance(),
&TextEditorSettings::fontSettingsChanged,
this, &SideBySideDiffEditorWidget::setFontSettings);
......@@ -678,7 +722,7 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
QVBoxLayout *l = new QVBoxLayout(this);
l->setMargin(0);
l->addWidget(m_splitter);
setFocusProxy(m_rightEditor);
setFocusProxy(m_leftEditor);
m_leftContext = new IContext(this);
m_leftContext->setWidget(m_leftEditor);
......@@ -1060,32 +1104,43 @@ void SideBySideDiffEditorWidget::leftCursorPositionChanged()
{
leftVSliderChanged();
leftHSliderChanged();
if (m_controller.m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
m_controller.m_ignoreCurrentIndexChange = true;
emit currentDiffFileIndexChanged(
m_leftEditor->fileIndexForBlockNumber(m_leftEditor->textCursor().blockNumber()));
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
handlePositionChange(m_leftEditor, m_rightEditor);
}
void SideBySideDiffEditorWidget::rightCursorPositionChanged()
{
rightVSliderChanged();
rightHSliderChanged();
handlePositionChange(m_rightEditor, m_leftEditor);
}
void SideBySideDiffEditorWidget::handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest)
{
if (m_controller.m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
m_controller.m_ignoreCurrentIndexChange = true;
syncCursor(source, dest);
emit currentDiffFileIndexChanged(
m_rightEditor->fileIndexForBlockNumber(m_rightEditor->textCursor().blockNumber()));
source->fileIndexForBlockNumber(source->textCursor().blockNumber()));
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::syncCursor(SideDiffEditorWidget *source, SideDiffEditorWidget *dest)
{
const QTextCursor sourceCursor = source->textCursor();
const int sourceLine = sourceCursor.blockNumber();
const int sourceColumn = sourceCursor.positionInBlock();
QTextCursor destCursor = dest->textCursor();
const QTextBlock destBlock = dest->document()->findBlockByNumber(sourceLine);
const int destColumn = qMin(sourceColumn, destBlock.length());
const int destPosition = destBlock.position() + destColumn;
destCursor.setPosition(destPosition);
dest->setTextCursor(destCursor);
}
} // namespace Internal
} // namespace DiffEditor
......
......@@ -95,6 +95,8 @@ private:
void rightHSliderChanged();
void leftCursorPositionChanged();
void rightCursorPositionChanged();
void handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest);
void syncCursor(SideDiffEditorWidget *source, SideDiffEditorWidget *dest);
void showDiff();
......
......@@ -58,7 +58,6 @@ UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
DisplaySettings settings = displaySettings();
settings.m_textWrapping = false;
settings.m_displayLineNumbers = true;
settings.m_highlightCurrentLine = false;
settings.m_markTextChanges = false;
settings.m_highlightBlocks = false;
SelectableTextEditorWidget::setDisplaySettings(settings);
......@@ -133,6 +132,8 @@ void UnifiedDiffEditorWidget::setDisplaySettings(const DisplaySettings &ds)
DisplaySettings settings = displaySettings();
settings.m_visualizeWhitespace = ds.m_visualizeWhitespace;
settings.m_displayFoldingMarkers = ds.m_displayFoldingMarkers;
settings.m_scrollBarHighlights = ds.m_scrollBarHighlights;
settings.m_highlightCurrentLine = ds.m_highlightCurrentLine;
SelectableTextEditorWidget::setDisplaySettings(settings);
}
......
......@@ -72,7 +72,7 @@
#include <coreplugin/infobar.h>
#include <coreplugin/manhattanstyle.h>
#include <coreplugin/find/basetextfind.h>
#include <coreplugin/find/highlightscrollbar.h>
#include <coreplugin/find/highlightscrollbarcontroller.h>
#include <utils/algorithm.h>
#include <utils/asconst.h>
#include <utils/textutils.h>
......@@ -759,7 +759,7 @@ public:
QFutureWatcher<FileSearchResultList> *m_searchWatcher = nullptr;
QVector<SearchResult> m_searchResults;
QTimer m_scrollBarUpdateTimer;
HighlightScrollBar *m_highlightScrollBar = nullptr;
HighlightScrollBarController *m_highlightScrollBarController = nullptr;
bool m_scrollBarUpdateScheduled = false;
};
......@@ -814,6 +814,7 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate()
this, &TextEditorWidgetPrivate::markRemoved);
q->disconnect(this);
delete m_toolBar;
delete m_highlightScrollBarController;
}
} // namespace Internal
......@@ -904,15 +905,15 @@ void TextEditorWidget::setTextDocument(const QSharedPointer<TextDocument> &doc)
void TextEditorWidgetPrivate::setupScrollBar()
{
if (m_displaySettings.m_scrollBarHighlights) {
if (m_highlightScrollBar)
return;
m_highlightScrollBar = new HighlightScrollBar(Qt::Vertical, q);
q->setVerticalScrollBar(m_highlightScrollBar);
if (!m_highlightScrollBarController)
m_highlightScrollBarController = new HighlightScrollBarController();
m_highlightScrollBarController->setScrollArea(q);
highlightSearchResultsInScrollBar();
scheduleUpdateHighlightScrollBar();
} else if (m_highlightScrollBar) {
q->setVerticalScrollBar(new QScrollBar(Qt::Vertical, q));
m_highlightScrollBar = 0;
} else if (m_highlightScrollBarController) {
delete m_highlightScrollBarController;
m_highlightScrollBarController = nullptr;
}
}
......@@ -5311,14 +5312,14 @@ void TextEditorWidgetPrivate::updateHighlights()
void TextEditorWidgetPrivate::updateCurrentLineInScrollbar()
{
if (m_highlightCurrentLine && m_highlightScrollBar) {
m_highlightScrollBar->removeHighlights(Constants::SCROLL_BAR_CURRENT_LINE);
if (m_highlightScrollBar->maximum() > 0) {
if (m_highlightCurrentLine && m_highlightScrollBarController) {
m_highlightScrollBarController->removeHighlights(Constants::SCROLL_BAR_CURRENT_LINE);
if (m_highlightScrollBarController->scrollBar()->maximum() > 0) {
const QTextCursor &tc = q->textCursor();
if (QTextLayout *layout = tc.block().layout()) {
const int pos = q->textCursor().block().firstLineNumber() +
layout->lineForTextPosition(tc.positionInBlock()).lineNumber();
m_highlightScrollBar->addHighlight({Constants::SCROLL_BAR_CURRENT_LINE, pos,
m_highlightScrollBarController->addHighlight({Constants::SCROLL_BAR_CURRENT_LINE, pos,
Theme::TextEditor_CurrentLine_ScrollBarColor,
Highlight::HighestPriority});
}
......@@ -6213,7 +6214,7 @@ void TextEditorWidgetPrivate::highlightSearchResultsSlot(const QString &txt, Fin
m_delayedUpdateTimer.start(50);
if (m_highlightScrollBar)
if (m_highlightScrollBarController)
m_scrollBarUpdateTimer.start(50);
}
......@@ -6241,22 +6242,22 @@ void TextEditorWidgetPrivate::searchFinished()
void TextEditorWidgetPrivate::adjustScrollBarRanges()
{
if (!m_highlightScrollBar)
if (!m_highlightScrollBarController)
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);
m_highlightScrollBarController->setVisibleRange((q->viewport()->rect().height() - offset) / lineSpacing);
m_highlightScrollBarController->setRangeOffset(offset / lineSpacing);
}
void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar()
{
if (!m_highlightScrollBar)
if (!m_highlightScrollBarController)
return;
m_highlightScrollBar->removeHighlights(Constants::SCROLL_BAR_SEARCH_RESULT);
m_highlightScrollBarController->removeHighlights(Constants::SCROLL_BAR_SEARCH_RESULT);
m_searchResults.clear();
if (m_searchWatcher) {
......@@ -6318,7 +6319,7 @@ Highlight::Priority textMarkPrioToScrollBarPrio(const TextMark::Priority &prio)
void TextEditorWidgetPrivate::addSearchResultsToScrollBar(QVector<SearchResult> results)
{
if (!m_highlightScrollBar)
if (!m_highlightScrollBarController)
return;
foreach (SearchResult result, results) {
const QTextBlock &block = q->document()->findBlock(result.start);
......@@ -6326,7 +6327,7 @@ void TextEditorWidgetPrivate::addSearchResultsToScrollBar(QVector<SearchResult>
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) {
m_highlightScrollBar->addHighlight(
m_highlightScrollBarController->addHighlight(
{Constants::SCROLL_BAR_SEARCH_RESULT, block.firstLineNumber() + line,
Theme::TextEditor_SearchResult_ScrollBarColor, Highlight::HighPriority});
}
......@@ -6343,10 +6344,10 @@ Highlight markToHighlight(TextMark *mark, int lineNumber)
void TextEditorWidgetPrivate::updateHighlightScrollBarNow()
{
m_scrollBarUpdateScheduled = false;
if (!m_highlightScrollBar)
if (!m_highlightScrollBarController)
return;
m_highlightScrollBar->removeAllHighlights();
m_highlightScrollBarController->removeAllHighlights();
updateCurrentLineInScrollbar();
......@@ -6359,7 +6360,7 @@ void TextEditorWidgetPrivate::updateHighlightScrollBarNow()
continue;
const QTextBlock &block = q->document()->findBlockByNumber(mark->lineNumber() - 1);
if (block.isVisible())
m_highlightScrollBar->addHighlight(markToHighlight(mark, block.firstLineNumber()));
m_highlightScrollBarController->addHighlight(markToHighlight(mark, block.firstLineNumber()));
}
}
......@@ -8376,6 +8377,11 @@ int TextEditorWidget::centerVisibleLine() const
return block.isValid() ? block.blockNumber() : -1;
}
HighlightScrollBarController *TextEditorWidget::highlightScrollBarController() const
{
return d->m_highlightScrollBarController;
}
bool TextEditorWidget::isMissingSyntaxDefinition() const
{
return d->m_isMissingSyntaxDefinition;
......
......@@ -51,6 +51,10 @@ class QRect;
class QTextBlock;
QT_END_NAMESPACE
namespace Core {
class HighlightScrollBarController;
}
namespace TextEditor {
class TextDocument;
class BaseHoverHandler;
......@@ -458,6 +462,8 @@ public:
/*! Returns the line visible closest to the vertical center of the editor. */
int centerVisibleLine() const;
Core::HighlightScrollBarController *highlightScrollBarController() const;
signals:
void assistFinished(); // Used in tests.
void readOnlyChanged();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment