Changeset View
Changeset View
Standalone View
Standalone View
documentation/standarddocumentationview.cpp
Show All 16 Lines | |||||
17 | * Free Software Foundation, Inc., | 17 | * Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | 19 | */ | ||
20 | 20 | | |||
21 | #include "standarddocumentationview.h" | 21 | #include "standarddocumentationview.h" | ||
22 | #include "documentationfindwidget.h" | 22 | #include "documentationfindwidget.h" | ||
23 | #include "debug.h" | 23 | #include "debug.h" | ||
24 | 24 | | |||
25 | #include <QVBoxLayout> | ||||
26 | | ||||
27 | #ifdef USE_QTWEBKIT | ||||
25 | #include <QFontDatabase> | 28 | #include <QFontDatabase> | ||
29 | #include <QWebView> | ||||
26 | #include <QWebFrame> | 30 | #include <QWebFrame> | ||
31 | #include <QWebSettings> | ||||
32 | #else | ||||
33 | #include <QNetworkRequest> | ||||
34 | #include <QNetworkReply> | ||||
35 | #include <QWebEngineView> | ||||
36 | #include <QWebEnginePage> | ||||
37 | #include <QWebEngineSettings> | ||||
38 | #include <QWebEngineUrlSchemeHandler> | ||||
39 | #include <QWebEngineUrlRequestJob> | ||||
40 | #include <QWebEngineProfile> | ||||
41 | #endif | ||||
27 | 42 | | |||
28 | using namespace KDevelop; | 43 | using namespace KDevelop; | ||
29 | 44 | | |||
45 | struct KDevelop::StandardDocumentationViewPrivate | ||||
46 | { | ||||
47 | IDocumentation::Ptr m_doc; | ||||
48 | | ||||
49 | #ifdef USE_QTWEBKIT | ||||
50 | QWebView *m_view = nullptr; | ||||
51 | void init(QWidget* parent) { m_view = new QWebView(parent); } | ||||
52 | #else | ||||
53 | QWebEngineView* m_view = nullptr; | ||||
54 | void init(QWidget* parent) { m_view = new QWebEngineView(parent); } | ||||
55 | #endif | ||||
56 | }; | ||||
57 | | ||||
30 | StandardDocumentationView::StandardDocumentationView(DocumentationFindWidget* findWidget, QWidget* parent) | 58 | StandardDocumentationView::StandardDocumentationView(DocumentationFindWidget* findWidget, QWidget* parent) | ||
31 | : QWebView(parent) | 59 | : QWidget(parent) | ||
60 | , d(new StandardDocumentationViewPrivate) | ||||
32 | { | 61 | { | ||
62 | setLayout(new QVBoxLayout(this)); | ||||
63 | d->init(this); | ||||
64 | layout()->addWidget(d->m_view); | ||||
65 | | ||||
33 | findWidget->setEnabled(true); | 66 | findWidget->setEnabled(true); | ||
34 | connect(findWidget, &DocumentationFindWidget::newSearch, this, &StandardDocumentationView::search); | 67 | connect(findWidget, &DocumentationFindWidget::newSearch, this, &StandardDocumentationView::search); | ||
35 | 68 | | |||
69 | #ifdef USE_QTWEBKIT | ||||
36 | QFont sansSerifFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); | 70 | QFont sansSerifFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); | ||
37 | QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); | 71 | QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); | ||
38 | QFont minimalFont = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); | 72 | QFont minimalFont = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); | ||
39 | 73 | | |||
40 | QWebSettings* s = settings(); | 74 | QWebSettings* s = d->m_view->settings(); | ||
41 | 75 | | |||
42 | s->setFontFamily(QWebSettings::StandardFont, sansSerifFont.family()); | 76 | s->setFontFamily(QWebSettings::StandardFont, sansSerifFont.family()); | ||
mwolff: all of this code here is now lost, don't we need it anymore? | |||||
43 | s->setFontFamily(QWebSettings::SerifFont, "Serif"); | 77 | s->setFontFamily(QWebSettings::SerifFont, "Serif"); | ||
44 | s->setFontFamily(QWebSettings::SansSerifFont, sansSerifFont.family()); | 78 | s->setFontFamily(QWebSettings::SansSerifFont, sansSerifFont.family()); | ||
45 | s->setFontFamily(QWebSettings::FixedFont, monospaceFont.family()); | 79 | s->setFontFamily(QWebSettings::FixedFont, monospaceFont.family()); | ||
46 | 80 | | |||
47 | s->setFontSize(QWebSettings::DefaultFontSize, QFontInfo(sansSerifFont).pixelSize()); | 81 | s->setFontSize(QWebSettings::DefaultFontSize, QFontInfo(sansSerifFont).pixelSize()); | ||
48 | s->setFontSize(QWebSettings::DefaultFixedFontSize, QFontInfo(monospaceFont).pixelSize()); | 82 | s->setFontSize(QWebSettings::DefaultFixedFontSize, QFontInfo(monospaceFont).pixelSize()); | ||
49 | s->setFontSize(QWebSettings::MinimumFontSize, QFontInfo(minimalFont).pixelSize()); | 83 | s->setFontSize(QWebSettings::MinimumFontSize, QFontInfo(minimalFont).pixelSize()); | ||
50 | 84 | | |||
51 | // Fixes for correct positioning. The problem looks like the following: | 85 | // Fixes for correct positioning. The problem looks like the following: | ||
52 | // | 86 | // | ||
53 | // 1) Some page is loaded and loadFinished() signal is emitted, | 87 | // 1) Some page is loaded and loadFinished() signal is emitted, | ||
54 | // after this QWebView set right position inside page. | 88 | // after this QWebView set right position inside page. | ||
55 | // | 89 | // | ||
56 | // 2) After loadFinished() emitting, page JS code finishes it's work and changes | 90 | // 2) After loadFinished() emitting, page JS code finishes it's work and changes | ||
57 | // font settings (size). This leads to page contents "moving" inside view widget | 91 | // font settings (size). This leads to page contents "moving" inside view widget | ||
58 | // and as a result we have wrong position. | 92 | // and as a result we have wrong position. | ||
59 | // | 93 | // | ||
60 | // Such behavior occurs for example with QtHelp pages. | 94 | // Such behavior occurs for example with QtHelp pages. | ||
61 | // | 95 | // | ||
62 | // To fix the problem, first, we disable view painter updates during load to avoid content | 96 | // To fix the problem, first, we disable view painter updates during load to avoid content | ||
63 | // "flickering" and also to hide font size "jumping". Secondly, we reset position inside page | 97 | // "flickering" and also to hide font size "jumping". Secondly, we reset position inside page | ||
64 | // after loading with using standard QWebFrame method scrollToAnchor(). | 98 | // after loading with using standard QWebFrame method scrollToAnchor(). | ||
65 | 99 | | |||
66 | connect(this, &QWebView::loadStarted, this, [this]() { | 100 | connect(d->m_view, &QWebView::loadStarted, d->m_view, [this]() { | ||
67 | setUpdatesEnabled(false); | 101 | d->m_view->setUpdatesEnabled(false); | ||
68 | }); | 102 | }); | ||
69 | 103 | | |||
70 | connect(this, &QWebView::loadFinished, this, [this](bool) { | 104 | connect(d->m_view, &QWebView::loadFinished, this, [this](bool) { | ||
71 | if (url().isValid()) { | 105 | if (d->m_view->url().isValid()) { | ||
72 | page()->mainFrame()->scrollToAnchor(url().fragment()); | 106 | d->m_view->page()->mainFrame()->scrollToAnchor(d->m_view->url().fragment()); | ||
73 | } | 107 | } | ||
74 | setUpdatesEnabled(true); | 108 | setUpdatesEnabled(true); | ||
75 | }); | 109 | }); | ||
76 | 110 | #endif | |||
77 | } | 111 | } | ||
78 | 112 | | |||
113 | KDevelop::StandardDocumentationView::~StandardDocumentationView() = default; | ||||
114 | | ||||
79 | void StandardDocumentationView::search ( const QString& text, DocumentationFindWidget::FindOptions options ) | 115 | void StandardDocumentationView::search ( const QString& text, DocumentationFindWidget::FindOptions options ) | ||
80 | { | 116 | { | ||
81 | //Highlighting has been commented because it doesn't let me jump around all occurrences | 117 | #ifdef USE_QTWEBKIT | ||
82 | // page()->findText(QString(), QWebPage::HighlightAllOccurrences); | 118 | typedef QWebPage WebkitThing; | ||
83 | 119 | #else | |||
84 | QWebPage::FindFlags ff=QWebPage::FindWrapsAroundDocument /*| QWebPage::HighlightAllOccurrences*/; | 120 | typedef QWebEnginePage WebkitThing; | ||
121 | #endif | ||||
122 | WebkitThing::FindFlags ff = 0; | ||||
85 | if(options & DocumentationFindWidget::Previous) | 123 | if(options & DocumentationFindWidget::Previous) | ||
86 | ff |= QWebPage::FindBackward; | 124 | ff |= WebkitThing::FindBackward; | ||
87 | 125 | | |||
88 | if(options & DocumentationFindWidget::MatchCase) | 126 | if(options & DocumentationFindWidget::MatchCase) | ||
89 | ff |= QWebPage::FindCaseSensitively; | 127 | ff |= WebkitThing::FindCaseSensitively; | ||
90 | 128 | | |||
91 | page()->findText(text, ff); | 129 | d->m_view->page()->findText(text, ff); | ||
92 | } | 130 | } | ||
93 | 131 | | |||
94 | void StandardDocumentationView::setDocumentation(const IDocumentation::Ptr& doc) | 132 | void StandardDocumentationView::setDocumentation(const IDocumentation::Ptr& doc) | ||
95 | { | 133 | { | ||
96 | if(m_doc) | 134 | if(d->m_doc) | ||
97 | disconnect(m_doc.data()); | 135 | disconnect(d->m_doc.data()); | ||
98 | m_doc = doc; | 136 | d->m_doc = doc; | ||
99 | update(); | 137 | update(); | ||
100 | if(m_doc) | 138 | if(d->m_doc) | ||
101 | connect(m_doc.data(), &IDocumentation::descriptionChanged, this, &StandardDocumentationView::update); | 139 | connect(d->m_doc.data(), &IDocumentation::descriptionChanged, this, &StandardDocumentationView::update); | ||
102 | } | 140 | } | ||
103 | 141 | | |||
104 | void StandardDocumentationView::update() | 142 | void StandardDocumentationView::update() | ||
105 | { | 143 | { | ||
106 | if(m_doc) | 144 | if(d->m_doc) { | ||
107 | setHtml(m_doc->description()); | 145 | setHtml(d->m_doc->description()); | ||
108 | else | 146 | } else | ||
109 | qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an uninitialized view"; | 147 | qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an uninitialized view"; | ||
110 | } | 148 | } | ||
149 | | ||||
150 | void KDevelop::StandardDocumentationView::setOverrideCss(const QUrl& url) | ||||
151 | { | ||||
152 | #ifdef USE_QTWEBKIT | ||||
153 | d->m_view->settings()->setUserStyleSheetUrl(url); | ||||
154 | #else | ||||
155 | d->m_view->page()->runJavaScript( | ||||
156 | "var link = document.createElement( 'link' );" | ||||
157 | "link.href = " + url.toString().toUtf8() + ";" | ||||
158 | "link.type = 'text/css';" | ||||
159 | "link.rel = 'stylesheet';" | ||||
160 | "link.media = 'screen,print';" | ||||
161 | "document.getElementsByTagName( 'head' )[0].appendChild( link );" | ||||
162 | ); | ||||
163 | #endif | ||||
164 | } | ||||
165 | | ||||
166 | void KDevelop::StandardDocumentationView::load(const QUrl& url) | ||||
167 | { | ||||
168 | #ifdef USE_QTWEBKIT | ||||
169 | d->m_view->load(url); | ||||
170 | #else | ||||
171 | d->m_view->page()->load(url); | ||||
172 | #endif | ||||
173 | } | ||||
174 | | ||||
175 | void KDevelop::StandardDocumentationView::setHtml(const QString& html) | ||||
176 | { | ||||
177 | #ifdef USE_QTWEBKIT | ||||
178 | d->m_view->setHtml(html); | ||||
179 | #else | ||||
180 | d->m_view->page()->setHtml(html); | ||||
181 | #endif | ||||
182 | } | ||||
183 | | ||||
184 | #ifndef USE_QTWEBKIT | ||||
185 | class CustomSchemeHandler : public QWebEngineUrlSchemeHandler | ||||
186 | { | ||||
187 | public: | ||||
188 | explicit CustomSchemeHandler(QNetworkAccessManager* nam, QObject *parent = 0) | ||||
189 | : QWebEngineUrlSchemeHandler(parent), m_nam(nam) {} | ||||
190 | | ||||
191 | void requestStarted(QWebEngineUrlRequestJob *job) override { | ||||
192 | const QUrl url = job->requestUrl(); | ||||
193 | | ||||
194 | auto reply = m_nam->get(QNetworkRequest(url)); | ||||
195 | job->reply("text/html", reply); | ||||
196 | } | ||||
197 | | ||||
198 | private: | ||||
199 | QNetworkAccessManager* m_nam; | ||||
200 | }; | ||||
201 | #endif | ||||
202 | | ||||
203 | void KDevelop::StandardDocumentationView::setNetworkAccessManager(QNetworkAccessManager* manager) | ||||
204 | { | ||||
205 | #ifdef USE_QTWEBKIT | ||||
206 | d->m_view->page()->setNetworkAccessManager(manager); | ||||
207 | #else | ||||
208 | d->m_view->page()->profile()->installUrlSchemeHandler("qthelp", new CustomSchemeHandler(manager, this)); | ||||
209 | #endif | ||||
210 | } | ||||
211 | | ||||
212 | #ifndef USE_QTWEBKIT | ||||
213 | class PageInterceptor : public QWebEnginePage | ||||
214 | { | ||||
215 | public: | ||||
216 | PageInterceptor(KDevelop::StandardDocumentationView* parent) : QWebEnginePage(parent), m_view(parent) {} | ||||
217 | | ||||
218 | bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool /*isMainFrame*/) override { | ||||
219 | qCDebug(DOCUMENTATION) << "navigating to..." << url << type; | ||||
220 | if (type == NavigationTypeLinkClicked) { | ||||
221 | m_view->load(url); | ||||
222 | return false; | ||||
223 | } | ||||
224 | return true; | ||||
225 | } | ||||
226 | | ||||
227 | KDevelop::StandardDocumentationView* m_view; | ||||
228 | }; | ||||
229 | #endif | ||||
230 | | ||||
231 | void KDevelop::StandardDocumentationView::setDelegateLinks(bool delegate) | ||||
232 | { | ||||
233 | #ifdef USE_QTWEBKIT | ||||
234 | d->m_view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); | ||||
235 | #else | ||||
236 | if (delegate) | ||||
237 | d->m_view->setPage(new PageInterceptor(this)); | ||||
238 | else | ||||
239 | d->m_view->setPage(new QWebEnginePage(this)); | ||||
240 | #endif | ||||
241 | } | ||||
242 | | ||||
243 | QAction * KDevelop::StandardDocumentationView::copyAction() const | ||||
244 | { | ||||
245 | #ifdef USE_QTWEBKIT | ||||
246 | typedef QWebPage WebkitThing; | ||||
247 | #else | ||||
248 | typedef QWebEnginePage WebkitThing; | ||||
249 | #endif | ||||
250 | return d->m_view->pageAction(WebkitThing::Copy); | ||||
251 | } |
all of this code here is now lost, don't we need it anymore?