Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtextbrowser.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtextbrowser.h"
5#include "qtextedit_p.h"
6
7#include <qstack.h>
8#include <qapplication.h>
9#include <private/qapplication_p.h>
10#include <qevent.h>
11#include <qdebug.h>
13#include "private/qtextdocumentlayout_p.h"
14#include <qpainter.h>
15#include <qdir.h>
16#if QT_CONFIG(whatsthis)
17#include <qwhatsthis.h>
18#endif
19#include <qtextobject.h>
20#include <qdesktopservices.h>
21#include <qstringconverter.h>
22
24
25using namespace Qt::StringLiterals;
26
27static inline bool shouldEnableInputMethod(QTextBrowser *texbrowser)
28{
29#if defined (Q_OS_ANDROID)
30 return !texbrowser->isReadOnly() || (texbrowser->textInteractionFlags() & Qt::TextSelectableByMouse);
31#else
32 return !texbrowser->isReadOnly();
33#endif
34}
35
36Q_LOGGING_CATEGORY(lcBrowser, "qt.text.browser")
37
39{
40 Q_DECLARE_PUBLIC(QTextBrowser)
41public:
43 : textOrSourceChanged(false), forceLoadOnSourceChange(false), openExternalLinks(false),
44 openLinks(true)
45#ifdef QT_KEYPAD_NAVIGATION
46 , lastKeypadScrollValue(-1)
47#endif
48 {}
54
55 void init();
56
57 struct HistoryEntry {
58 inline HistoryEntry()
59 : hpos(0), vpos(0), focusIndicatorPosition(-1),
60 focusIndicatorAnchor(-1) {}
63 int hpos;
64 int vpos;
65 int focusIndicatorPosition, focusIndicatorAnchor;
67 };
68
70 {
71 if (i <= 0)
72 if (-i < stack.size())
73 return stack[stack.size()+i-1];
74 else
75 return HistoryEntry();
76 else
77 if (i <= forwardStack.size())
78 return forwardStack[forwardStack.size()-i];
79 else
80 return HistoryEntry();
81 }
82
83
84 HistoryEntry createHistoryEntry() const;
85 void restoreHistoryEntry(const HistoryEntry &entry);
86
87 QStack<HistoryEntry> stack;
88 QStack<HistoryEntry> forwardStack;
91
93
94 /*flag necessary to give the linkClicked() signal some meaningful
95 semantics when somebody connected to it calls setText() or
96 setSource() */
99
102
104
105#ifndef QT_NO_CURSOR
107#endif
108
109 QString findFile(const QUrl &name) const;
110
111 inline void documentModified()
112 {
113 textOrSourceChanged = true;
114 forceLoadOnSourceChange = !currentURL.path().isEmpty();
115 }
116
117 void activateAnchor(const QString &href);
118 void highlightLink(const QString &href);
119
120 void setSource(const QUrl &url, QTextDocument::ResourceType type);
121
122 // re-imlemented from QTextEditPrivate
123 virtual QUrl resolveUrl(const QUrl &url) const override;
124 inline QUrl resolveUrl(const QString &url) const
125 { return resolveUrl(QUrl(url)); }
126
127#ifdef QT_KEYPAD_NAVIGATION
128 void keypadMove(bool next);
129 QTextCursor prevFocus;
130 int lastKeypadScrollValue;
131#endif
133 {
134 Q_Q(QTextBrowser);
135 emit q->highlighted(url);
136 }
137 std::array<QMetaObject::Connection, 3> connections;
138};
140
142{
144 if (name.scheme() == "qrc"_L1) {
145 fileName = ":/"_L1 + name.path();
146 } else if (name.scheme().isEmpty()) {
147 fileName = name.path();
148 } else {
149#if defined(Q_OS_ANDROID)
150 if (name.scheme() == "assets"_L1)
151 fileName = "assets:"_L1 + name.path();
152 else
153#endif
154 fileName = name.toLocalFile();
155 }
156
157 if (fileName.isEmpty())
158 return fileName;
159
160 if (QFileInfo(fileName).isAbsolute())
161 return fileName;
162
163 for (QString path : std::as_const(searchPaths)) {
164 if (!path.endsWith(u'/'))
165 path.append(u'/');
168 return path;
169 }
170
171 return fileName;
172}
173
175{
176 if (!url.isRelative())
177 return url;
178
179 // For the second case QUrl can merge "#someanchor" with "foo.html"
180 // correctly to "foo.html#someanchor"
181 if (!(currentURL.isRelative()
182 || (currentURL.scheme() == "file"_L1
184 || (url.hasFragment() && url.path().isEmpty())) {
185 return currentURL.resolved(url);
186 }
187
188 // this is our last resort when current url and new url are both relative
189 // we try to resolve against the current working directory in the local
190 // file system.
192 if (fi.exists()) {
193 return QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(url);
194 }
195
196 return url;
197}
198
200{
201 if (href.isEmpty())
202 return;
203 Q_Q(QTextBrowser);
204
205#ifndef QT_NO_CURSOR
206 viewport->setCursor(oldCursor);
207#endif
208
209 const QUrl url = resolveUrl(href);
210
211 if (!openLinks) {
212 emit q->anchorClicked(url);
213 return;
214 }
215
216 textOrSourceChanged = false;
217
218#ifndef QT_NO_DESKTOPSERVICES
219 bool isFileScheme =
220 url.scheme() == "file"_L1
221#if defined(Q_OS_ANDROID)
222 || url.scheme() == "assets"_L1
223#endif
224 || url.scheme() == "qrc"_L1;
225 if ((openExternalLinks && !isFileScheme && !url.isRelative())
226 || (url.isRelative() && !currentURL.isRelative() && !isFileScheme)) {
228 return;
229 }
230#endif
231
232 emit q->anchorClicked(url);
233
235 return;
236
237 q->setSource(url);
238}
239
241{
242 if (anchor.isEmpty()) {
243#ifndef QT_NO_CURSOR
244 if (viewport->cursor().shape() != Qt::PointingHandCursor)
245 oldCursor = viewport->cursor();
246 viewport->setCursor(oldCursor);
247#endif
249 } else {
250#ifndef QT_NO_CURSOR
252#endif
253
254 const QUrl url = resolveUrl(anchor);
256 }
257}
258
260{
261 Q_Q(QTextBrowser);
262#ifndef QT_NO_CURSOR
263 if (q->isVisible())
265#endif
266 textOrSourceChanged = true;
267
268 QString txt;
269
270 bool doSetText = false;
271
272 QUrl currentUrlWithoutFragment = currentURL;
273 currentUrlWithoutFragment.setFragment(QString());
274 QUrl newUrlWithoutFragment = currentURL.resolved(url);
275 newUrlWithoutFragment.setFragment(QString());
278#if QT_CONFIG(textmarkdownreader)
279 if (fileName.endsWith(".md"_L1) ||
280 fileName.endsWith(".mkd"_L1) ||
281 fileName.endsWith(".markdown"_L1))
283 else
284#endif
286 }
288
289 if (url.isValid()
290 && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) {
291 QVariant data = q->loadResource(type, resolveUrl(url));
292 if (data.userType() == QMetaType::QString) {
293 txt = data.toString();
294 } else if (data.userType() == QMetaType::QByteArray) {
295 QByteArray ba = data.toByteArray();
297 auto decoder = QStringDecoder::decoderForHtml(ba);
298 if (!decoder.isValid())
299 // fall back to utf8
301 txt = decoder(ba);
302 } else {
304 }
305 }
306 if (Q_UNLIKELY(txt.isEmpty()))
307 qWarning("QTextBrowser: No document for %s", url.toString().toLatin1().constData());
308
309 if (q->isVisible()) {
310 const QStringView firstTag = QStringView{txt}.left(txt.indexOf(u'>') + 1);
311 if (firstTag.startsWith("<qt"_L1) && firstTag.contains("type"_L1) && firstTag.contains("detail"_L1)) {
312#ifndef QT_NO_CURSOR
314#endif
315#if QT_CONFIG(whatsthis)
317#endif
318 return;
319 }
320 }
321
323 doSetText = true;
324 }
325
326 if (!home.isValid())
327 home = url;
328
329 if (doSetText) {
330 // Setting the base URL helps QTextDocument::resource() to find resources with relative paths.
331 // But don't set it unless it contains the document's path, because QTextBrowserPrivate::resolveUrl()
332 // can already deal with local files on the filesystem in case the base URL was not set.
334 if (!baseUrl.path().isEmpty())
335 q->document()->setBaseUrl(baseUrl);
336 q->document()->setMetaInformation(QTextDocument::DocumentUrl, currentURL.toString());
337 qCDebug(lcBrowser) << "loading" << currentURL << "base" << q->document()->baseUrl() << "type" << type << txt.size() << "chars";
338#if QT_CONFIG(textmarkdownreader)
340 q->QTextEdit::setMarkdown(txt);
341 else
342#endif
343#ifndef QT_NO_TEXTHTMLPARSER
344 q->QTextEdit::setHtml(txt);
345#else
346 q->QTextEdit::setPlainText(txt);
347#endif
348
349#ifdef QT_KEYPAD_NAVIGATION
350 prevFocus.movePosition(QTextCursor::Start);
351#endif
352 }
353
355
356 if (!url.fragment().isEmpty()) {
357 q->scrollToAnchor(url.fragment());
358 } else {
359 hbar->setValue(0);
360 vbar->setValue(0);
361 }
362#ifdef QT_KEYPAD_NAVIGATION
363 lastKeypadScrollValue = vbar->value();
365#endif
366
367#ifndef QT_NO_CURSOR
368 if (q->isVisible())
370#endif
371 emit q->sourceChanged(url);
372}
373
374#ifdef QT_KEYPAD_NAVIGATION
375void QTextBrowserPrivate::keypadMove(bool next)
376{
377 Q_Q(QTextBrowser);
378
379 const int height = viewport->height();
380 const int overlap = qBound(20, height / 5, 40); // XXX arbitrary, but a good balance
381 const int visibleLinkAmount = overlap; // consistent, but maybe not the best choice (?)
382 int yOffset = vbar->value();
383 int scrollYOffset = qBound(0, next ? yOffset + height - overlap : yOffset - height + overlap, vbar->maximum());
384
385 bool foundNextAnchor = false;
386 bool focusIt = false;
387 int focusedPos = -1;
388
389 QTextCursor anchorToFocus;
390
391 QRectF viewRect = QRectF(0, yOffset, control->size().width(), height);
392 QRectF newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
393 QRectF bothViewRects = viewRect.united(newViewRect);
394
395 // If we don't have a previous anchor, pretend that we had the first/last character
396 // on the screen selected.
397 if (prevFocus.isNull()) {
398 if (next)
399 prevFocus = control->cursorForPosition(QPointF(0, yOffset));
400 else
401 prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
402 }
403
404 // First, check to see if someone has moved the scroll bars independently
405 if (lastKeypadScrollValue != yOffset) {
406 // Someone (user or programmatically) has moved us, so we might
407 // need to start looking from the current position instead of prevFocus
408
409 bool findOnScreen = true;
410
411 // If prevFocus is on screen at all, we just use it.
412 if (prevFocus.hasSelection()) {
413 QRectF prevRect = control->selectionRect(prevFocus);
414 if (viewRect.intersects(prevRect))
415 findOnScreen = false;
416 }
417
418 // Otherwise, we find a new anchor that's on screen.
419 // Basically, create a cursor with the last/first character
420 // on screen
421 if (findOnScreen) {
422 if (next)
423 prevFocus = control->cursorForPosition(QPointF(0, yOffset));
424 else
425 prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
426 }
427 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
428 } else if (prevFocus.hasSelection()) {
429 // Check the pathological case that the current anchor is higher
430 // than the screen, and just scroll through it in that case
431 QRectF prevRect = control->selectionRect(prevFocus);
432 if ((next && prevRect.bottom() > (yOffset + height)) ||
433 (!next && prevRect.top() < yOffset)) {
434 anchorToFocus = prevFocus;
435 focusedPos = scrollYOffset;
436 focusIt = true;
437 } else {
438 // This is the "normal" case - no scroll bar adjustments, no large anchors,
439 // and no wrapping.
440 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
441 }
442 }
443
444 // If not found yet, see if we need to wrap
445 if (!focusIt && !foundNextAnchor) {
446 if (next) {
447 if (yOffset == vbar->maximum()) {
448 prevFocus.movePosition(QTextCursor::Start);
449 yOffset = scrollYOffset = 0;
450
451 // Refresh the rectangles
452 viewRect = QRectF(0, yOffset, control->size().width(), height);
453 newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
454 bothViewRects = viewRect.united(newViewRect);
455 }
456 } else {
457 if (yOffset == 0) {
458 prevFocus.movePosition(QTextCursor::End);
459 yOffset = scrollYOffset = vbar->maximum();
460
461 // Refresh the rectangles
462 viewRect = QRectF(0, yOffset, control->size().width(), height);
463 newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
464 bothViewRects = viewRect.united(newViewRect);
465 }
466 }
467
468 // Try looking now
469 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
470 }
471
472 // If we did actually find an anchor to use...
473 if (foundNextAnchor) {
474 QRectF desiredRect = control->selectionRect(anchorToFocus);
475
476 // XXX This is an arbitrary heuristic
477 // Decide to focus an anchor if it will be at least be
478 // in the middle region of the screen after a scroll.
479 // This can result in partial anchors with focus, but
480 // insisting on links being completely visible before
481 // selecting them causes disparities between links that
482 // take up 90% of the screen height and those that take
483 // up e.g. 110%
484 // Obviously if a link is entirely visible, we still
485 // focus it.
486 if (bothViewRects.contains(desiredRect)
487 || bothViewRects.adjusted(0, visibleLinkAmount, 0, -visibleLinkAmount).intersects(desiredRect)) {
488 focusIt = true;
489
490 // We aim to put the new link in the middle of the screen,
491 // unless the link is larger than the screen (we just move to
492 // display the first page of the link)
493 if (desiredRect.height() > height) {
494 if (next)
495 focusedPos = (int) desiredRect.top();
496 else
497 focusedPos = (int) desiredRect.bottom() - height;
498 } else
499 focusedPos = (int) ((desiredRect.top() + desiredRect.bottom()) / 2 - (height / 2));
500
501 // and clamp it to make sure we don't skip content.
502 if (next)
503 focusedPos = qBound(yOffset, focusedPos, scrollYOffset);
504 else
505 focusedPos = qBound(scrollYOffset, focusedPos, yOffset);
506 }
507 }
508
509 // If we didn't get a new anchor, check if the old one is still on screen when we scroll
510 // Note that big (larger than screen height) anchors also have some handling at the
511 // start of this function.
512 if (!focusIt && prevFocus.hasSelection()) {
513 QRectF desiredRect = control->selectionRect(prevFocus);
514 // XXX this may be better off also using the visibleLinkAmount value
515 if (newViewRect.intersects(desiredRect)) {
516 focusedPos = scrollYOffset;
517 focusIt = true;
518 anchorToFocus = prevFocus;
519 }
520 }
521
522 // setTextCursor ensures that the cursor is visible. save & restore
523 // the scroll bar values therefore
524 const int savedXOffset = hbar->value();
525
526 // Now actually process our decision
527 if (focusIt && control->setFocusToAnchor(anchorToFocus)) {
528 // Save the focus for next time
529 prevFocus = control->textCursor();
530
531 // Scroll
532 vbar->setValue(focusedPos);
533 lastKeypadScrollValue = focusedPos;
534 hbar->setValue(savedXOffset);
535
536 // Ensure that the new selection is highlighted.
537 const QString href = control->anchorAtCursor();
538 QUrl url = resolveUrl(href);
540 } else {
541 // Scroll
542 vbar->setValue(scrollYOffset);
543 lastKeypadScrollValue = scrollYOffset;
544
545 // now make sure we don't have a focused anchor
547 cursor.clearSelection();
548
550
551 hbar->setValue(savedXOffset);
552 vbar->setValue(scrollYOffset);
553
555 }
556}
557#endif
558
560{
562 entry.url = q_func()->source();
563 entry.type = q_func()->sourceType();
564 entry.title = q_func()->documentTitle();
565 entry.hpos = hbar->value();
566 entry.vpos = vbar->value();
567
570 && cursor.hasSelection()) {
571
572 entry.focusIndicatorPosition = cursor.position();
573 entry.focusIndicatorAnchor = cursor.anchor();
574 }
575 return entry;
576}
577
579{
580 setSource(entry.url, entry.type);
581 hbar->setValue(entry.hpos);
582 vbar->setValue(entry.vpos);
583 if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) {
585 cursor.setPosition(entry.focusIndicatorAnchor);
586 cursor.setPosition(entry.focusIndicatorPosition, QTextCursor::KeepAnchor);
589 }
590#ifdef QT_KEYPAD_NAVIGATION
591 lastKeypadScrollValue = vbar->value();
592 prevFocus = control->textCursor();
593
594 Q_Q(QTextBrowser);
595 const QString href = prevFocus.charFormat().anchorHref();
596 QUrl url = resolveUrl(href);
598#endif
599}
600
688
693 : QTextEdit(*new QTextBrowserPrivate, parent)
694{
695 Q_D(QTextBrowser);
696 d->init();
697}
698
699
706
735{
736 Q_D(const QTextBrowser);
737 if (d->stack.isEmpty())
738 return QUrl();
739 else
740 return d->stack.top().url;
741}
742
752{
753 Q_D(const QTextBrowser);
754 if (d->stack.isEmpty())
756 else
757 return d->stack.top().type;
758}
759
771{
772 Q_D(const QTextBrowser);
773 return d->searchPaths;
774}
775
777{
778 Q_D(QTextBrowser);
779 d->searchPaths = paths;
780}
781
786{
787 Q_D(QTextBrowser);
788 QUrl s = d->currentURL;
789 d->currentURL = QUrl();
790 setSource(s, d->currentType);
791}
792
807
815{
816 Q_D(QTextBrowser);
817
818 const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry();
819
820 d->setSource(url, type);
821
822 if (!url.isValid())
823 return;
824
825 // the same url you are already watching?
826 if (!d->stack.isEmpty() && d->stack.top().url == url)
827 return;
828
829 if (!d->stack.isEmpty())
830 d->stack.top() = historyEntry;
831
833 entry.url = url;
834 entry.type = d->currentType;
835 entry.title = documentTitle();
836 entry.hpos = 0;
837 entry.vpos = 0;
838 d->stack.push(entry);
839
840 emit backwardAvailable(d->stack.size() > 1);
841
842 if (!d->forwardStack.isEmpty() && d->forwardStack.top().url == url) {
843 d->forwardStack.pop();
844 emit forwardAvailable(d->forwardStack.size() > 0);
845 } else {
846 d->forwardStack.clear();
847 emit forwardAvailable(false);
848 }
849
851}
852
916{
917 Q_D(QTextBrowser);
918 if (d->stack.size() <= 1)
919 return;
920
921 // Update the history entry
922 d->forwardStack.push(d->createHistoryEntry());
923 d->stack.pop(); // throw away the old version of the current entry
924 d->restoreHistoryEntry(d->stack.top()); // previous entry
925 emit backwardAvailable(d->stack.size() > 1);
928}
929
938{
939 Q_D(QTextBrowser);
940 if (d->forwardStack.isEmpty())
941 return;
942 if (!d->stack.isEmpty()) {
943 // Update the history entry
944 d->stack.top() = d->createHistoryEntry();
945 }
946 d->stack.push(d->forwardStack.pop());
947 d->restoreHistoryEntry(d->stack.top());
949 emit forwardAvailable(!d->forwardStack.isEmpty());
951}
952
958{
959 Q_D(QTextBrowser);
960 if (d->home.isValid())
961 setSource(d->home);
962}
963
974{
975#ifdef QT_KEYPAD_NAVIGATION
976 Q_D(QTextBrowser);
977 switch (ev->key()) {
978 case Qt::Key_Select:
979 if (QApplicationPrivate::keypadNavigationEnabled()) {
980 if (!hasEditFocus()) {
981 setEditFocus(true);
982 return;
983 } else {
984 QTextCursor cursor = d->control->textCursor();
985 QTextCharFormat charFmt = cursor.charFormat();
986 if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
987 ev->accept();
988 return;
989 }
990 }
991 }
992 break;
993 case Qt::Key_Back:
994 if (QApplicationPrivate::keypadNavigationEnabled()) {
995 if (hasEditFocus()) {
996 setEditFocus(false);
997 ev->accept();
998 return;
999 }
1000 }
1002 return;
1003 default:
1004 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()) {
1005 ev->ignore();
1006 return;
1007 }
1008 }
1009#endif
1010
1011 if (ev->modifiers() & Qt::AltModifier) {
1012 switch (ev->key()) {
1013 case Qt::Key_Right:
1014 forward();
1015 ev->accept();
1016 return;
1017 case Qt::Key_Left:
1018 backward();
1019 ev->accept();
1020 return;
1021 case Qt::Key_Up:
1022 home();
1023 ev->accept();
1024 return;
1025 }
1026 }
1027#ifdef QT_KEYPAD_NAVIGATION
1028 else {
1029 if (ev->key() == Qt::Key_Up) {
1030 d->keypadMove(false);
1031 return;
1032 } else if (ev->key() == Qt::Key_Down) {
1033 d->keypadMove(true);
1034 return;
1035 }
1036 }
1037#endif
1039}
1040
1048
1056
1064
1069{
1070#ifndef QT_NO_CURSOR
1071 Q_D(QTextBrowser);
1072 d->viewport->setCursor((!(d->control->textInteractionFlags() & Qt::TextEditable)) ? d->oldCursor : Qt::IBeamCursor);
1073#endif
1075}
1076
1081{
1082 Q_D(QTextBrowser);
1083 if (d->control->setFocusToNextOrPreviousAnchor(next)) {
1084#ifdef QT_KEYPAD_NAVIGATION
1085 // Might need to synthesize a highlight event.
1086 if (d->prevFocus != d->control->textCursor() && d->control->textCursor().hasSelection()) {
1087 const QString href = d->control->anchorAtCursor();
1088 QUrl url = d->resolveUrl(href);
1089 emitHighlighted(url);
1090 }
1091 d->prevFocus = d->control->textCursor();
1092#endif
1093 return true;
1094 } else {
1095#ifdef QT_KEYPAD_NAVIGATION
1096 // We assume we have no highlight now.
1097 emitHighlighted(QUrl());
1098#endif
1099 }
1101}
1102
1107{
1108 Q_D(QTextBrowser);
1109 QPainter p(d->viewport);
1110 d->paint(&p, e);
1111}
1112
1139{
1140 Q_D(QTextBrowser);
1141
1143 QString fileName = d->findFile(d->resolveUrl(name));
1144 if (fileName.isEmpty())
1145 return QVariant();
1146 QFile f(fileName);
1147 if (f.open(QFile::ReadOnly)) {
1148 data = f.readAll();
1149 f.close();
1150 } else {
1151 return QVariant();
1152 }
1153
1154 return data;
1155}
1156
1166{
1167 Q_D(const QTextBrowser);
1168 return d->stack.size() > 1;
1169}
1170
1180{
1181 Q_D(const QTextBrowser);
1182 return !d->forwardStack.isEmpty();
1183}
1184
1194{
1195 Q_D(QTextBrowser);
1196 d->forwardStack.clear();
1197 if (!d->stack.isEmpty()) {
1198 QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top();
1199 d->stack.clear();
1200 d->stack.push(historyEntry);
1201 d->home = historyEntry.url;
1202 }
1203 emit forwardAvailable(false);
1204 emit backwardAvailable(false);
1206}
1207
1221{
1222 Q_D(const QTextBrowser);
1223 return d->history(i).url;
1224}
1225
1241{
1242 Q_D(const QTextBrowser);
1243 return d->history(i).title;
1244}
1245
1246
1253{
1254 Q_D(const QTextBrowser);
1255 return d->forwardStack.size();
1256}
1257
1264{
1265 Q_D(const QTextBrowser);
1266 return d->stack.size()-1;
1267}
1268
1281{
1282 Q_D(const QTextBrowser);
1283 return d->openExternalLinks;
1284}
1285
1287{
1288 Q_D(QTextBrowser);
1289 d->openExternalLinks = open;
1290}
1291
1305{
1306 Q_D(const QTextBrowser);
1307 return d->openLinks;
1308}
1309
1311{
1312 Q_D(QTextBrowser);
1313 d->openLinks = open;
1314}
1315
1318{
1319 return QTextEdit::event(e);
1320}
1321
1323
1324#include "moc_qtextbrowser.cpp"
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
The QCursor class provides a mouse cursor with an arbitrary shape.
Definition qcursor.h:45
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
static bool openUrl(const QUrl &url)
Opens the given url in the appropriate Web browser for the user's desktop environment,...
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:209
\inmodule QtCore
Definition qcoreevent.h:45
bool isAbsolute() const
Returns true if the file system entry's path is absolute, otherwise returns false (that is,...
Definition qfileinfo.h:120
bool isReadable() const
Returns true if the user can read the file system entry this QFileInfo refers to; otherwise returns f...
\inmodule QtCore
Definition qfile.h:93
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:470
static void setOverrideCursor(const QCursor &)
Sets the application override cursor to cursor.
static void restoreOverrideCursor()
Undoes the last setOverrideCursor().
The QKeyEvent class describes a key event.
Definition qevent.h:424
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
\inmodule QtGui
Definition qevent.h:196
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:486
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:498
QRectF united(const QRectF &other) const noexcept
Definition qrect.h:852
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
\inmodule QtCore
static Q_CORE_EXPORT QStringDecoder decoderForHtml(QByteArrayView data)
Tries to determine the encoding of the HTML in data by looking at leading byte order marks or a chars...
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView left(qsizetype n) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QString & append(QChar c)
Definition qstring.cpp:3252
QUrl resolveUrl(const QString &url) const
QTextDocument::ResourceType currentType
void restoreHistoryEntry(const HistoryEntry &entry)
std::array< QMetaObject::Connection, 3 > connections
void activateAnchor(const QString &href)
void emitHighlighted(const QUrl &url)
void highlightLink(const QString &href)
HistoryEntry history(int i) const
QStack< HistoryEntry > stack
QStack< HistoryEntry > forwardStack
HistoryEntry createHistoryEntry() const
QString findFile(const QUrl &name) const
QStringList searchPaths
virtual QUrl resolveUrl(const QUrl &url) const override
void setSource(const QUrl &url, QTextDocument::ResourceType type)
The QTextBrowser class provides a rich text browser with hypertext navigation.
virtual void focusOutEvent(QFocusEvent *ev) override
\reimp
virtual void mouseMoveEvent(QMouseEvent *ev) override
\reimp
void setSearchPaths(const QStringList &paths)
bool event(QEvent *e) override
\reimp
virtual void backward()
Changes the document displayed to the previous document in the list of documents built by navigating ...
void backwardAvailable(bool)
This signal is emitted when the availability of backward() changes.
virtual ~QTextBrowser()
int backwardHistoryCount() const
Returns the number of locations backward in the history.
QUrl historyUrl(int) const
Returns the url of the HistoryItem.
virtual bool focusNextPrevChild(bool next) override
\reimp
virtual void mousePressEvent(QMouseEvent *ev) override
\reimp
virtual QVariant loadResource(int type, const QUrl &name) override
This function is called when the document is loaded and for each image in the document.
QStringList searchPaths
the search paths used by the text browser to find supporting content
QTextDocument::ResourceType sourceType
the type of the displayed document
virtual void paintEvent(QPaintEvent *e) override
\reimp
bool isForwardAvailable() const
int forwardHistoryCount() const
Returns the number of locations forward in the history.
virtual void doSetSource(const QUrl &name, QTextDocument::ResourceType type=QTextDocument::UnknownResource)
Attempts to load the document at the given url with the specified type.
virtual void reload()
Reloads the current set source.
virtual void home()
Changes the document displayed to be the first document from the history.
virtual void keyPressEvent(QKeyEvent *ev) override
The event ev is used to provide the following keyboard shortcuts: \table \header.
void setOpenLinks(bool open)
void historyChanged()
bool isBackwardAvailable() const
QTextBrowser(QWidget *parent=nullptr)
Constructs an empty QTextBrowser with parent parent.
bool openExternalLinks
void setOpenExternalLinks(bool open)
void setSource(const QUrl &name, QTextDocument::ResourceType type=QTextDocument::UnknownResource)
Attempts to load the document at the given url with the specified type.
virtual void forward()
Changes the document displayed to the next document in the list of documents built by navigating link...
void forwardAvailable(bool)
This signal is emitted when the availability of forward() changes.
QUrl source
the name of the displayed document.
virtual void mouseReleaseEvent(QMouseEvent *ev) override
\reimp
QString historyTitle(int) const
Returns the documentTitle() of the HistoryItem.
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
ResourceType
This enum describes the types of resources that can be loaded by QTextDocument's loadResource() funct...
void contentsChanged()
This signal is emitted whenever the document's content changes; for example, when text is inserted or...
QWidgetTextControl * control
Definition qtextedit_p.h:81
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition qtextedit.h:27
virtual void mousePressEvent(QMouseEvent *e) override
\reimp
virtual bool focusNextPrevChild(bool next) override
\reimp
virtual void mouseReleaseEvent(QMouseEvent *e) override
\reimp
QString documentTitle
the title of the document parsed from the text.
Definition qtextedit.h:32
virtual void keyPressEvent(QKeyEvent *e) override
\reimp
virtual void mouseMoveEvent(QMouseEvent *e) override
\reimp
virtual bool event(QEvent *e) override
virtual void focusOutEvent(QFocusEvent *e) override
\reimp
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
QString fragment(ComponentFormattingOptions options=PrettyDecoded) const
Returns the fragment of the URL.
Definition qurl.cpp:2682
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2497
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2725
void setFragment(const QString &fragment, ParsingMode mode=TolerantMode)
Sets the fragment of the URL to fragment.
Definition qurl.cpp:2648
bool hasFragment() const
Definition qurl.cpp:2700
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2800
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
QUrl adjusted(FormattingOptions options) const
Definition qurl.cpp:2924
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
@ RemoveFilename
Definition qurl.h:116
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3425
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2468
\inmodule QtCore
Definition qvariant.h:65
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
static void showText(const QPoint &pos, const QString &text, QWidget *w=nullptr)
Shows text as a "What's This?" window, at global position pos.
QTextCursor textCursor() const
void setCursorIsFocusIndicator(bool b)
void setTextCursor(const QTextCursor &cursor, bool selectionClipboard=false)
void linkActivated(const QString &link)
QTextCursor cursorForPosition(const QPointF &pos) const
bool setFocusToAnchor(const QTextCursor &newCursor)
bool findNextPrevAnchor(const QTextCursor &from, bool next, QTextCursor &newAnchor)
QString anchorAtCursor() const
QRectF selectionRect(const QTextCursor &cursor) const
bool cursorIsFocusIndicator() const
void linkHovered(const QString &)
QTextDocument * document() const
void setTextInteractionFlags(Qt::TextInteractionFlags flags)
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QCursor cursor
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ TextSelectableByMouse
@ TextEditable
@ TextBrowserInteraction
@ WA_InputMethodEnabled
Definition qnamespace.h:295
@ PointingHandCursor
@ WaitCursor
@ IBeamCursor
@ Key_Select
@ Key_Right
Definition qnamespace.h:679
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_Back
Definition qnamespace.h:846
@ AltModifier
#define Q_UNLIKELY(x)
DBusConnection * connection
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
GLint GLsizei GLsizei height
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum type
GLsizei const GLuint * paths
GLuint name
GLdouble s
[6]
Definition qopenglext.h:235
GLuint entry
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
static QString findFile(const QDir &dir, const QString &baseName, const QStringList &extensions)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
static bool shouldEnableInputMethod(QTextBrowser *texbrowser)
#define emit
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:158
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:180
QByteArray ba
[0]
file open(QIODevice::ReadOnly)
QUrl url("example.com")
[constructor-url-reference]
QUrl baseUrl
Text files * txt
view viewport() -> scroll(dx, dy, deviceRect)