12#include <QtCore/QStringBuilder>
14#include <QtGui/QContextMenuEvent>
15#include <QtWidgets/QMenu>
16#include <QtWidgets/QScrollBar>
17#if QT_CONFIG(clipboard)
18#include <QtGui/QClipboard>
20#include <QtWidgets/QApplication>
24HelpViewerImpl::HelpViewerImpl(qreal zoom, QWidget *parent)
25 : QTextBrowser(parent)
26 , d(
new HelpViewerImplPrivate(zoom))
29 QPalette p = palette();
30 p.setColor(QPalette::Inactive, QPalette::Highlight,
31 p.color(QPalette::Active, QPalette::Highlight));
32 p.setColor(QPalette::Inactive, QPalette::HighlightedText,
33 p.color(QPalette::Active, QPalette::HighlightedText));
36 installEventFilter(
this);
37 document()->setDocumentMargin(8);
39 QFont font = viewerFont();
40 font.setPointSize(
int(font.pointSize() + zoom));
43 connect(
this, &QTextBrowser::sourceChanged,
this, &HelpViewerImpl::titleChanged);
44 connect(
this, &HelpViewerImpl::loadFinished,
this, &HelpViewerImpl::setLoadFinished);
47QFont HelpViewerImpl::viewerFont()
const
50 if (HelpEngineWrapper::instance().usesBrowserFont())
51 return HelpEngineWrapper::instance().browserFont();
55void HelpViewerImpl::setViewerFont(
const QFont &newFont)
58 if (font() != newFont) {
65void HelpViewerImpl::scaleUp()
68 if (d->zoomCount < 10) {
76void HelpViewerImpl::scaleDown()
79 if (d->zoomCount > -5) {
87void HelpViewerImpl::resetScale()
90 if (d->zoomCount != 0) {
92 zoomOut(d->zoomCount);
98qreal HelpViewerImpl::scale()
const
104QString HelpViewerImpl::title()
const
107 return documentTitle();
110QUrl HelpViewerImpl::source()
const
113 return QTextBrowser::source();
116void HelpViewerImpl::doSetSource(
const QUrl &url, QTextDocument::ResourceType type)
120 if (HelpViewer::launchWithExternalApp(url))
123 bool helpOrAbout = (url.toString() ==
"help"_L1);
124 const QUrl resolvedUrl = (helpOrAbout ? LocalHelpFile : HelpEngineWrapper::instance().findFile(url));
126 QTextBrowser::doSetSource(resolvedUrl, type);
128 if (!resolvedUrl.isValid()) {
129 helpOrAbout = (url.toString() ==
"about:blank"_L1);
130 setHtml(helpOrAbout ? AboutBlank : PageNotFoundMessage.arg(url.toString()));
132 emit loadFinished(
true);
135QString HelpViewerImpl::selectedText()
const
138 return textCursor().selectedText();
141bool HelpViewerImpl::isForwardAvailable()
const
144 return QTextBrowser::isForwardAvailable();
147bool HelpViewerImpl::isBackwardAvailable()
const
150 return QTextBrowser::isBackwardAvailable();
153bool HelpViewerImpl::findText(
const QString &text, HelpViewer::FindFlags flags,
bool incremental,
157 QTextDocument *doc = document();
158 QTextCursor cursor = textCursor();
159 if (!doc || cursor.isNull())
162 const int position = cursor.selectionStart();
164 cursor.setPosition(position);
166 QTextDocument::FindFlags textDocFlags;
167 if (flags & HelpViewer::FindBackward)
168 textDocFlags |= QTextDocument::FindBackward;
169 if (flags & HelpViewer::FindCaseSensitively)
170 textDocFlags |= QTextDocument::FindCaseSensitively;
172 QTextCursor found = doc->find(text, cursor, textDocFlags);
173 if (found.isNull()) {
174 if ((flags & HelpViewer::FindBackward) == 0)
175 cursor.movePosition(QTextCursor::Start);
177 cursor.movePosition(QTextCursor::End);
178 found = doc->find(text, cursor, textDocFlags);
182 cursor.beginEditBlock();
183 viewport()->setUpdatesEnabled(
false);
185 QTextCharFormat marker;
186 marker.setForeground(Qt::red);
187 cursor.movePosition(QTextCursor::Start);
188 setTextCursor(cursor);
191 QTextCursor hit = textCursor();
192 hit.mergeCharFormat(marker);
195 viewport()->setUpdatesEnabled(
true);
196 cursor.endEditBlock();
199 bool cursorIsNull = found.isNull();
201 found = textCursor();
202 found.setPosition(position);
204 setTextCursor(found);
205 return !cursorIsNull;
210#if QT_CONFIG(clipboard)
211void HelpViewerImpl::copy()
214 QTextBrowser::copy();
218void HelpViewerImpl::forward()
221 QTextBrowser::forward();
224void HelpViewerImpl::backward()
227 QTextBrowser::backward();
232void HelpViewerImpl::keyPressEvent(QKeyEvent *e)
235 if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
236 || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
237 QKeyEvent* event =
new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
238 e->text(), e->isAutoRepeat(), e->count());
241 QTextBrowser::keyPressEvent(e);
244void HelpViewerImpl::wheelEvent(QWheelEvent *e)
247 if (e->modifiers() == Qt::ControlModifier) {
249 e->angleDelta().y() > 0 ? scaleUp() : scaleDown();
251 QTextBrowser::wheelEvent(e);
255void HelpViewerImpl::mousePressEvent(QMouseEvent *e)
259 if (handleForwardBackwardMouseButtons(e))
263 QTextBrowser::mousePressEvent(e);
266void HelpViewerImpl::mouseReleaseEvent(QMouseEvent *e)
270 if (handleForwardBackwardMouseButtons(e))
274 bool controlPressed = e->modifiers() & Qt::ControlModifier;
275 if ((controlPressed && d->hasAnchorAt(
this, e->pos())) ||
276 (e->button() == Qt::MiddleButton && d->hasAnchorAt(
this, e->pos()))) {
277 d->openLinkInNewPage();
281 QTextBrowser::mouseReleaseEvent(e);
285void HelpViewerImpl::resizeEvent(QResizeEvent *e)
287 const int topTextPosition = cursorForPosition({width() / 2, 0}).position();
288 QTextBrowser::resizeEvent(e);
289 scrollToTextPosition(topTextPosition);
294void HelpViewerImpl::actionChanged()
302bool HelpViewerImpl::eventFilter(QObject *obj, QEvent *event)
305 if (event->type() == QEvent::FontChange && !d->forceFont)
307 return QTextBrowser::eventFilter(obj, event);
310void HelpViewerImpl::contextMenuEvent(QContextMenuEvent *event)
314 QMenu menu(QString(),
nullptr);
316#if QT_CONFIG(clipboard)
317 QAction *copyAnchorAction =
nullptr;
319 if (d->hasAnchorAt(
this, event->pos())) {
320 link = anchorAt(event->pos());
321 if (link.isRelative())
322 link = source().resolved(link);
323 menu.addAction(tr(
"Open Link"), d, &HelpViewerImplPrivate::openLink);
324 menu.addAction(tr(
"Open Link in New Tab\tCtrl+LMB"), d, &HelpViewerImplPrivate::openLinkInNewPage);
326#if QT_CONFIG(clipboard)
327 if (!link.isEmpty() && link.isValid())
328 copyAnchorAction = menu.addAction(tr(
"Copy &Link Location"));
330 }
else if (!selectedText().isEmpty()) {
331#if QT_CONFIG(clipboard)
332 menu.addAction(tr(
"Copy"),
this, &HelpViewerImpl::copy);
335 menu.addAction(tr(
"Reload"),
this, &HelpViewerImpl::reload);
338#if QT_CONFIG(clipboard)
339 if (copyAnchorAction == menu.exec(event->globalPos()))
340 QApplication::clipboard()->setText(link.toString());
344QVariant HelpViewerImpl::loadResource(
int type,
const QUrl &name)
349 const QUrl url = HelpEngineWrapper::instance().findFile(name);
350 ba = HelpEngineWrapper::instance().fileData(url);
351 if (url.toString().endsWith(
".svg"_L1, Qt::CaseInsensitive)) {
353 image.loadFromData(ba,
"svg");
362void HelpViewerImpl::scrollToTextPosition(
int position)
364 QTextCursor tc(document());
365 tc.setPosition(position);
366 const int dy = cursorRect(tc).top();
367 if (verticalScrollBar()) {
368 verticalScrollBar()->setValue(
369 std::min(verticalScrollBar()->value() + dy, verticalScrollBar()->maximum()));
Combined button and popup list for selecting options.