diff --git a/documentation/standarddocumentationview.cpp b/documentation/standarddocumentationview.cpp --- a/documentation/standarddocumentationview.cpp +++ b/documentation/standarddocumentationview.cpp @@ -22,12 +22,84 @@ #include "documentationfindwidget.h" #include "debug.h" +#include #include +#include +#include using namespace KDevelop; +class StandardDocumentationViewHelper : public QObject +{ + Q_OBJECT +public: + StandardDocumentationViewHelper(StandardDocumentationView* view); + + bool eventFilter(QObject* target, QEvent* event); + +private: + void adjustPosition(); + + StandardDocumentationView* m_view; +}; + +StandardDocumentationViewHelper::StandardDocumentationViewHelper(StandardDocumentationView* view) + : QObject(view) + , m_view(view) +{ + Q_ASSERT(view); + + m_view->installEventFilter(this); + + // First, we disable view painter updates during load to avoid content "flickering" and + // also to hide font size "jumping", which happens for example for Qt help pages with + // JavaScript enabled. This JS also breaks positioning inside page: + // + // 1) Some page is loaded (for example QWebView::setUrl()) and loadFinished() signal + // emitted, then view set right position inside page. + // + // 2) After this, page JS finishes it's work and change font settings (size). + // This leads to contents "moving" inside view and as a result we have wrong position. + // + // Therefore secondly, we fix position after loading with using standard QWebFrame method + // scrollToAnchor() to avoid page reloading which happens if view's methods like + // load() or setUrl() are used. + // + // Such positioning fixing also applied on resize event - standard view's behavior breaks + // position during widget resize. + + connect(m_view, &QWebView::loadStarted, this, [this]() { + m_view->setUpdatesEnabled(false); + }); + + connect(m_view, &QWebView::loadFinished, this, [this](bool) { + adjustPosition(); + m_view->setUpdatesEnabled(true); + }); +} + +bool StandardDocumentationViewHelper::eventFilter(QObject* target, QEvent* event) +{ + bool result = QObject::eventFilter(target, event); + + if (event->type() == QEvent::Resize) { + adjustPosition(); + } + + return result; +} + +void StandardDocumentationViewHelper::adjustPosition() +{ + if (!m_view->url().isValid()) { + return; + } + + m_view->page()->mainFrame()->scrollToAnchor(m_view->url().fragment()); +} + StandardDocumentationView::StandardDocumentationView(DocumentationFindWidget* findWidget, QWidget* parent) - : QWebView (parent) + : QWebView(parent) { findWidget->setEnabled(true); connect(findWidget, &DocumentationFindWidget::newSearch, this, &StandardDocumentationView::search); @@ -46,6 +118,8 @@ s->setFontSize(QWebSettings::DefaultFontSize, QFontInfo(sansSerifFont).pixelSize()); s->setFontSize(QWebSettings::DefaultFixedFontSize, QFontInfo(monospaceFont).pixelSize()); s->setFontSize(QWebSettings::MinimumFontSize, QFontInfo(minimalFont).pixelSize()); + + new StandardDocumentationViewHelper(this); } void StandardDocumentationView::search ( const QString& text, DocumentationFindWidget::FindOptions options ) @@ -80,3 +154,5 @@ else qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an uninitialized view"; } + +#include "standarddocumentationview.moc"