Qt 6.x
The Qt SDK
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 {}
49
50 void init();
51
52 struct HistoryEntry {
53 inline HistoryEntry()
54 : hpos(0), vpos(0), focusIndicatorPosition(-1),
55 focusIndicatorAnchor(-1) {}
58 int hpos;
59 int vpos;
60 int focusIndicatorPosition, focusIndicatorAnchor;
62 };
63
65 {
66 if (i <= 0)
67 if (-i < stack.size())
68 return stack[stack.size()+i-1];
69 else
70 return HistoryEntry();
71 else
72 if (i <= forwardStack.size())
73 return forwardStack[forwardStack.size()-i];
74 else
75 return HistoryEntry();
76 }
77
78
79 HistoryEntry createHistoryEntry() const;
80 void restoreHistoryEntry(const HistoryEntry &entry);
81
86
88
89 /*flag necessary to give the linkClicked() signal some meaningful
90 semantics when somebody connected to it calls setText() or
91 setSource() */
94
97
99
100#ifndef QT_NO_CURSOR
102#endif
103
104 QString findFile(const QUrl &name) const;
105
107 {
108 textOrSourceChanged = true;
109 forceLoadOnSourceChange = !currentURL.path().isEmpty();
110 }
111
112 void _q_activateAnchor(const QString &href);
113 void _q_highlightLink(const QString &href);
114
115 void setSource(const QUrl &url, QTextDocument::ResourceType type);
116
117 // re-imlemented from QTextEditPrivate
118 virtual QUrl resolveUrl(const QUrl &url) const override;
119 inline QUrl resolveUrl(const QString &url) const
120 { return resolveUrl(QUrl(url)); }
121
122#ifdef QT_KEYPAD_NAVIGATION
123 void keypadMove(bool next);
124 QTextCursor prevFocus;
125 int lastKeypadScrollValue;
126#endif
128 {
129 Q_Q(QTextBrowser);
130 emit q->highlighted(url);
131 }
132};
134
136{
138 if (name.scheme() == "qrc"_L1) {
139 fileName = ":/"_L1 + name.path();
140 } else if (name.scheme().isEmpty()) {
141 fileName = name.path();
142 } else {
143#if defined(Q_OS_ANDROID)
144 if (name.scheme() == "assets"_L1)
145 fileName = "assets:"_L1 + name.path();
146 else
147#endif
148 fileName = name.toLocalFile();
149 }
150
151 if (fileName.isEmpty())
152 return fileName;
153
154 if (QFileInfo(fileName).isAbsolute())
155 return fileName;
156
157 for (QString path : std::as_const(searchPaths)) {
158 if (!path.endsWith(u'/'))
159 path.append(u'/');
160 path.append(fileName);
162 return path;
163 }
164
165 return fileName;
166}
167
169{
170 if (!url.isRelative())
171 return url;
172
173 // For the second case QUrl can merge "#someanchor" with "foo.html"
174 // correctly to "foo.html#someanchor"
175 if (!(currentURL.isRelative()
176 || (currentURL.scheme() == "file"_L1
178 || (url.hasFragment() && url.path().isEmpty())) {
179 return currentURL.resolved(url);
180 }
181
182 // this is our last resort when current url and new url are both relative
183 // we try to resolve against the current working directory in the local
184 // file system.
186 if (fi.exists()) {
188 }
189
190 return url;
191}
192
194{
195 if (href.isEmpty())
196 return;
197 Q_Q(QTextBrowser);
198
199#ifndef QT_NO_CURSOR
200 viewport->setCursor(oldCursor);
201#endif
202
203 const QUrl url = resolveUrl(href);
204
205 if (!openLinks) {
206 emit q->anchorClicked(url);
207 return;
208 }
209
210 textOrSourceChanged = false;
211
212#ifndef QT_NO_DESKTOPSERVICES
213 bool isFileScheme =
214 url.scheme() == "file"_L1
215#if defined(Q_OS_ANDROID)
216 || url.scheme() == "assets"_L1
217#endif
218 || url.scheme() == "qrc"_L1;
219 if ((openExternalLinks && !isFileScheme && !url.isRelative())
220 || (url.isRelative() && !currentURL.isRelative() && !isFileScheme)) {
222 return;
223 }
224#endif
225
226 emit q->anchorClicked(url);
227
229 return;
230
231 q->setSource(url);
232}
233
235{
236 if (anchor.isEmpty()) {
237#ifndef QT_NO_CURSOR
238 if (viewport->cursor().shape() != Qt::PointingHandCursor)
239 oldCursor = viewport->cursor();
240 viewport->setCursor(oldCursor);
241#endif
243 } else {
244#ifndef QT_NO_CURSOR
246#endif
247
248 const QUrl url = resolveUrl(anchor);
250 }
251}
252
254{
255 Q_Q(QTextBrowser);
256#ifndef QT_NO_CURSOR
257 if (q->isVisible())
259#endif
260 textOrSourceChanged = true;
261
262 QString txt;
263
264 bool doSetText = false;
265
266 QUrl currentUrlWithoutFragment = currentURL;
267 currentUrlWithoutFragment.setFragment(QString());
268 QUrl newUrlWithoutFragment = currentURL.resolved(url);
269 newUrlWithoutFragment.setFragment(QString());
272#if QT_CONFIG(textmarkdownreader)
273 if (fileName.endsWith(".md"_L1) ||
274 fileName.endsWith(".mkd"_L1) ||
275 fileName.endsWith(".markdown"_L1))
277 else
278#endif
280 }
282
283 if (url.isValid()
284 && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) {
285 QVariant data = q->loadResource(type, resolveUrl(url));
286 if (data.userType() == QMetaType::QString) {
287 txt = data.toString();
288 } else if (data.userType() == QMetaType::QByteArray) {
289 QByteArray ba = data.toByteArray();
291 auto decoder = QStringDecoder::decoderForHtml(ba);
292 if (!decoder.isValid())
293 // fall back to utf8
295 txt = decoder(ba);
296 } else {
298 }
299 }
300 if (Q_UNLIKELY(txt.isEmpty()))
301 qWarning("QTextBrowser: No document for %s", url.toString().toLatin1().constData());
302
303 if (q->isVisible()) {
304 const QStringView firstTag = QStringView{txt}.left(txt.indexOf(u'>') + 1);
305 if (firstTag.startsWith("<qt"_L1) && firstTag.contains("type"_L1) && firstTag.contains("detail"_L1)) {
306#ifndef QT_NO_CURSOR
308#endif
309#if QT_CONFIG(whatsthis)
311#endif
312 return;
313 }
314 }
315
317 doSetText = true;
318 }
319
320 if (!home.isValid())
321 home = url;
322
323 if (doSetText) {
324 // Setting the base URL helps QTextDocument::resource() to find resources with relative paths.
325 // But don't set it unless it contains the document's path, because QTextBrowserPrivate::resolveUrl()
326 // can already deal with local files on the filesystem in case the base URL was not set.
328 if (!baseUrl.path().isEmpty())
329 q->document()->setBaseUrl(baseUrl);
330 q->document()->setMetaInformation(QTextDocument::DocumentUrl, currentURL.toString());
331 qCDebug(lcBrowser) << "loading" << currentURL << "base" << q->document()->baseUrl() << "type" << type << txt.size() << "chars";
332#if QT_CONFIG(textmarkdownreader)
334 q->QTextEdit::setMarkdown(txt);
335 else
336#endif
337#ifndef QT_NO_TEXTHTMLPARSER
338 q->QTextEdit::setHtml(txt);
339#else
340 q->QTextEdit::setPlainText(txt);
341#endif
342
343#ifdef QT_KEYPAD_NAVIGATION
344 prevFocus.movePosition(QTextCursor::Start);
345#endif
346 }
347
349
350 if (!url.fragment().isEmpty()) {
351 q->scrollToAnchor(url.fragment());
352 } else {
353 hbar->setValue(0);
354 vbar->setValue(0);
355 }
356#ifdef QT_KEYPAD_NAVIGATION
357 lastKeypadScrollValue = vbar->value();
359#endif
360
361#ifndef QT_NO_CURSOR
362 if (q->isVisible())
364#endif
365 emit q->sourceChanged(url);
366}
367
368#ifdef QT_KEYPAD_NAVIGATION
369void QTextBrowserPrivate::keypadMove(bool next)
370{
371 Q_Q(QTextBrowser);
372
373 const int height = viewport->height();
374 const int overlap = qBound(20, height / 5, 40); // XXX arbitrary, but a good balance
375 const int visibleLinkAmount = overlap; // consistent, but maybe not the best choice (?)
376 int yOffset = vbar->value();
377 int scrollYOffset = qBound(0, next ? yOffset + height - overlap : yOffset - height + overlap, vbar->maximum());
378
379 bool foundNextAnchor = false;
380 bool focusIt = false;
381 int focusedPos = -1;
382
383 QTextCursor anchorToFocus;
384
385 QRectF viewRect = QRectF(0, yOffset, control->size().width(), height);
386 QRectF newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
387 QRectF bothViewRects = viewRect.united(newViewRect);
388
389 // If we don't have a previous anchor, pretend that we had the first/last character
390 // on the screen selected.
391 if (prevFocus.isNull()) {
392 if (next)
393 prevFocus = control->cursorForPosition(QPointF(0, yOffset));
394 else
395 prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
396 }
397
398 // First, check to see if someone has moved the scroll bars independently
399 if (lastKeypadScrollValue != yOffset) {
400 // Someone (user or programmatically) has moved us, so we might
401 // need to start looking from the current position instead of prevFocus
402
403 bool findOnScreen = true;
404
405 // If prevFocus is on screen at all, we just use it.
406 if (prevFocus.hasSelection()) {
407 QRectF prevRect = control->selectionRect(prevFocus);
408 if (viewRect.intersects(prevRect))
409 findOnScreen = false;
410 }
411
412 // Otherwise, we find a new anchor that's on screen.
413 // Basically, create a cursor with the last/first character
414 // on screen
415 if (findOnScreen) {
416 if (next)
417 prevFocus = control->cursorForPosition(QPointF(0, yOffset));
418 else
419 prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
420 }
421 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
422 } else if (prevFocus.hasSelection()) {
423 // Check the pathological case that the current anchor is higher
424 // than the screen, and just scroll through it in that case
425 QRectF prevRect = control->selectionRect(prevFocus);
426 if ((next && prevRect.bottom() > (yOffset + height)) ||
427 (!next && prevRect.top() < yOffset)) {
428 anchorToFocus = prevFocus;
429 focusedPos = scrollYOffset;
430 focusIt = true;
431 } else {
432 // This is the "normal" case - no scroll bar adjustments, no large anchors,
433 // and no wrapping.
434 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
435 }
436 }
437
438 // If not found yet, see if we need to wrap
439 if (!focusIt && !foundNextAnchor) {
440 if (next) {
441 if (yOffset == vbar->maximum()) {
442 prevFocus.movePosition(QTextCursor::Start);
443 yOffset = scrollYOffset = 0;
444
445 // Refresh the rectangles
446 viewRect = QRectF(0, yOffset, control->size().width(), height);
447 newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
448 bothViewRects = viewRect.united(newViewRect);
449 }
450 } else {
451 if (yOffset == 0) {
452 prevFocus.movePosition(QTextCursor::End);
453 yOffset = scrollYOffset = vbar->maximum();
454
455 // Refresh the rectangles
456 viewRect = QRectF(0, yOffset, control->size().width(), height);
457 newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
458 bothViewRects = viewRect.united(newViewRect);
459 }
460 }
461
462 // Try looking now
463 foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
464 }
465
466 // If we did actually find an anchor to use...
467 if (foundNextAnchor) {
468 QRectF desiredRect = control->selectionRect(anchorToFocus);
469
470 // XXX This is an arbitrary heuristic
471 // Decide to focus an anchor if it will be at least be
472 // in the middle region of the screen after a scroll.
473 // This can result in partial anchors with focus, but
474 // insisting on links being completely visible before
475 // selecting them causes disparities between links that
476 // take up 90% of the screen height and those that take
477 // up e.g. 110%
478 // Obviously if a link is entirely visible, we still
479 // focus it.
480 if (bothViewRects.contains(desiredRect)
481 || bothViewRects.adjusted(0, visibleLinkAmount, 0, -visibleLinkAmount).intersects(desiredRect)) {
482 focusIt = true;
483
484 // We aim to put the new link in the middle of the screen,
485 // unless the link is larger than the screen (we just move to
486 // display the first page of the link)
487 if (desiredRect.height() > height) {
488 if (next)
489 focusedPos = (int) desiredRect.top();
490 else
491 focusedPos = (int) desiredRect.bottom() - height;
492 } else
493 focusedPos = (int) ((desiredRect.top() + desiredRect.bottom()) / 2 - (height / 2));
494
495 // and clamp it to make sure we don't skip content.
496 if (next)
497 focusedPos = qBound(yOffset, focusedPos, scrollYOffset);
498 else
499 focusedPos = qBound(scrollYOffset, focusedPos, yOffset);
500 }
501 }
502
503 // If we didn't get a new anchor, check if the old one is still on screen when we scroll
504 // Note that big (larger than screen height) anchors also have some handling at the
505 // start of this function.
506 if (!focusIt && prevFocus.hasSelection()) {
507 QRectF desiredRect = control->selectionRect(prevFocus);
508 // XXX this may be better off also using the visibleLinkAmount value
509 if (newViewRect.intersects(desiredRect)) {
510 focusedPos = scrollYOffset;
511 focusIt = true;
512 anchorToFocus = prevFocus;
513 }
514 }
515
516 // setTextCursor ensures that the cursor is visible. save & restore
517 // the scroll bar values therefore
518 const int savedXOffset = hbar->value();
519
520 // Now actually process our decision
521 if (focusIt && control->setFocusToAnchor(anchorToFocus)) {
522 // Save the focus for next time
523 prevFocus = control->textCursor();
524
525 // Scroll
526 vbar->setValue(focusedPos);
527 lastKeypadScrollValue = focusedPos;
528 hbar->setValue(savedXOffset);
529
530 // Ensure that the new selection is highlighted.
531 const QString href = control->anchorAtCursor();
532 QUrl url = resolveUrl(href);
534 } else {
535 // Scroll
536 vbar->setValue(scrollYOffset);
537 lastKeypadScrollValue = scrollYOffset;
538
539 // now make sure we don't have a focused anchor
541 cursor.clearSelection();
542
544
545 hbar->setValue(savedXOffset);
546 vbar->setValue(scrollYOffset);
547
549 }
550}
551#endif
552
554{
556 entry.url = q_func()->source();
557 entry.type = q_func()->sourceType();
558 entry.title = q_func()->documentTitle();
559 entry.hpos = hbar->value();
560 entry.vpos = vbar->value();
561
564 && cursor.hasSelection()) {
565
566 entry.focusIndicatorPosition = cursor.position();
567 entry.focusIndicatorAnchor = cursor.anchor();
568 }
569 return entry;
570}
571
573{
574 setSource(entry.url, entry.type);
575 hbar->setValue(entry.hpos);
576 vbar->setValue(entry.vpos);
577 if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) {
579 cursor.setPosition(entry.focusIndicatorAnchor);
580 cursor.setPosition(entry.focusIndicatorPosition, QTextCursor::KeepAnchor);
583 }
584#ifdef QT_KEYPAD_NAVIGATION
585 lastKeypadScrollValue = vbar->value();
586 prevFocus = control->textCursor();
587
588 Q_Q(QTextBrowser);
589 const QString href = prevFocus.charFormat().anchorHref();
590 QUrl url = resolveUrl(href);
592#endif
593}
594
664{
665 Q_Q(QTextBrowser);
667#ifndef QT_NO_CURSOR
668 viewport->setCursor(oldCursor);
669#endif
671 q->setUndoRedoEnabled(false);
672 viewport->setMouseTracking(true);
673 QObject::connect(q->document(), SIGNAL(contentsChanged()), q, SLOT(_q_documentModified()));
674 QObject::connect(control, SIGNAL(linkActivated(QString)),
676 QObject::connect(control, SIGNAL(linkHovered(QString)),
678}
679
685{
686 Q_D(QTextBrowser);
687 d->init();
688}
689
690
695{
696}
697
726{
727 Q_D(const QTextBrowser);
728 if (d->stack.isEmpty())
729 return QUrl();
730 else
731 return d->stack.top().url;
732}
733
743{
744 Q_D(const QTextBrowser);
745 if (d->stack.isEmpty())
747 else
748 return d->stack.top().type;
749}
750
762{
763 Q_D(const QTextBrowser);
764 return d->searchPaths;
765}
766
768{
769 Q_D(QTextBrowser);
770 d->searchPaths = paths;
771}
772
777{
778 Q_D(QTextBrowser);
779 QUrl s = d->currentURL;
780 d->currentURL = QUrl();
781 setSource(s, d->currentType);
782}
783
795{
797}
798
806{
807 Q_D(QTextBrowser);
808
809 const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry();
810
811 d->setSource(url, type);
812
813 if (!url.isValid())
814 return;
815
816 // the same url you are already watching?
817 if (!d->stack.isEmpty() && d->stack.top().url == url)
818 return;
819
820 if (!d->stack.isEmpty())
821 d->stack.top() = historyEntry;
822
824 entry.url = url;
825 entry.type = d->currentType;
826 entry.title = documentTitle();
827 entry.hpos = 0;
828 entry.vpos = 0;
829 d->stack.push(entry);
830
831 emit backwardAvailable(d->stack.size() > 1);
832
833 if (!d->forwardStack.isEmpty() && d->forwardStack.top().url == url) {
834 d->forwardStack.pop();
835 emit forwardAvailable(d->forwardStack.size() > 0);
836 } else {
837 d->forwardStack.clear();
838 emit forwardAvailable(false);
839 }
840
842}
843
907{
908 Q_D(QTextBrowser);
909 if (d->stack.size() <= 1)
910 return;
911
912 // Update the history entry
913 d->forwardStack.push(d->createHistoryEntry());
914 d->stack.pop(); // throw away the old version of the current entry
915 d->restoreHistoryEntry(d->stack.top()); // previous entry
916 emit backwardAvailable(d->stack.size() > 1);
919}
920
929{
930 Q_D(QTextBrowser);
931 if (d->forwardStack.isEmpty())
932 return;
933 if (!d->stack.isEmpty()) {
934 // Update the history entry
935 d->stack.top() = d->createHistoryEntry();
936 }
937 d->stack.push(d->forwardStack.pop());
938 d->restoreHistoryEntry(d->stack.top());
940 emit forwardAvailable(!d->forwardStack.isEmpty());
942}
943
949{
950 Q_D(QTextBrowser);
951 if (d->home.isValid())
952 setSource(d->home);
953}
954
965{
966#ifdef QT_KEYPAD_NAVIGATION
967 Q_D(QTextBrowser);
968 switch (ev->key()) {
969 case Qt::Key_Select:
970 if (QApplicationPrivate::keypadNavigationEnabled()) {
971 if (!hasEditFocus()) {
972 setEditFocus(true);
973 return;
974 } else {
975 QTextCursor cursor = d->control->textCursor();
976 QTextCharFormat charFmt = cursor.charFormat();
977 if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
978 ev->accept();
979 return;
980 }
981 }
982 }
983 break;
984 case Qt::Key_Back:
985 if (QApplicationPrivate::keypadNavigationEnabled()) {
986 if (hasEditFocus()) {
987 setEditFocus(false);
988 ev->accept();
989 return;
990 }
991 }
993 return;
994 default:
995 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()) {
996 ev->ignore();
997 return;
998 }
999 }
1000#endif
1001
1002 if (ev->modifiers() & Qt::AltModifier) {
1003 switch (ev->key()) {
1004 case Qt::Key_Right:
1005 forward();
1006 ev->accept();
1007 return;
1008 case Qt::Key_Left:
1009 backward();
1010 ev->accept();
1011 return;
1012 case Qt::Key_Up:
1013 home();
1014 ev->accept();
1015 return;
1016 }
1017 }
1018#ifdef QT_KEYPAD_NAVIGATION
1019 else {
1020 if (ev->key() == Qt::Key_Up) {
1021 d->keypadMove(false);
1022 return;
1023 } else if (ev->key() == Qt::Key_Down) {
1024 d->keypadMove(true);
1025 return;
1026 }
1027 }
1028#endif
1030}
1031
1036{
1038}
1039
1044{
1046}
1047
1052{
1054}
1055
1060{
1061#ifndef QT_NO_CURSOR
1062 Q_D(QTextBrowser);
1063 d->viewport->setCursor((!(d->control->textInteractionFlags() & Qt::TextEditable)) ? d->oldCursor : Qt::IBeamCursor);
1064#endif
1066}
1067
1072{
1073 Q_D(QTextBrowser);
1074 if (d->control->setFocusToNextOrPreviousAnchor(next)) {
1075#ifdef QT_KEYPAD_NAVIGATION
1076 // Might need to synthesize a highlight event.
1077 if (d->prevFocus != d->control->textCursor() && d->control->textCursor().hasSelection()) {
1078 const QString href = d->control->anchorAtCursor();
1079 QUrl url = d->resolveUrl(href);
1080 emitHighlighted(url);
1081 }
1082 d->prevFocus = d->control->textCursor();
1083#endif
1084 return true;
1085 } else {
1086#ifdef QT_KEYPAD_NAVIGATION
1087 // We assume we have no highlight now.
1088 emitHighlighted(QUrl());
1089#endif
1090 }
1092}
1093
1098{
1099 Q_D(QTextBrowser);
1100 QPainter p(d->viewport);
1101 d->paint(&p, e);
1102}
1103
1130{
1131 Q_D(QTextBrowser);
1132
1134 QString fileName = d->findFile(d->resolveUrl(name));
1135 if (fileName.isEmpty())
1136 return QVariant();
1137 QFile f(fileName);
1138 if (f.open(QFile::ReadOnly)) {
1139 data = f.readAll();
1140 f.close();
1141 } else {
1142 return QVariant();
1143 }
1144
1145 return data;
1146}
1147
1157{
1158 Q_D(const QTextBrowser);
1159 return d->stack.size() > 1;
1160}
1161
1171{
1172 Q_D(const QTextBrowser);
1173 return !d->forwardStack.isEmpty();
1174}
1175
1185{
1186 Q_D(QTextBrowser);
1187 d->forwardStack.clear();
1188 if (!d->stack.isEmpty()) {
1189 QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top();
1190 d->stack.clear();
1191 d->stack.push(historyEntry);
1192 d->home = historyEntry.url;
1193 }
1194 emit forwardAvailable(false);
1195 emit backwardAvailable(false);
1197}
1198
1212{
1213 Q_D(const QTextBrowser);
1214 return d->history(i).url;
1215}
1216
1232{
1233 Q_D(const QTextBrowser);
1234 return d->history(i).title;
1235}
1236
1237
1244{
1245 Q_D(const QTextBrowser);
1246 return d->forwardStack.size();
1247}
1248
1255{
1256 Q_D(const QTextBrowser);
1257 return d->stack.size()-1;
1258}
1259
1272{
1273 Q_D(const QTextBrowser);
1274 return d->openExternalLinks;
1275}
1276
1278{
1279 Q_D(QTextBrowser);
1280 d->openExternalLinks = open;
1281}
1282
1296{
1297 Q_D(const QTextBrowser);
1298 return d->openLinks;
1299}
1300
1302{
1303 Q_D(QTextBrowser);
1304 d->openLinks = open;
1305}
1306
1309{
1310 return QTextEdit::event(e);
1311}
1312
1314
1315#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:122
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:206
\inmodule QtCore
Definition qcoreevent.h:45
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
Definition qcoreevent.h:306
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:305
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString absolutePath() const
Returns a file's path absolute path.
bool isAbsolute() const
Returns true if the file path is absolute, otherwise returns false (i.e.
Definition qfileinfo.h:116
bool exists() const
Returns true if the file exists; otherwise returns false.
bool isReadable() const
Returns true if the user can read the file; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:469
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:423
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1465
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:433
\inmodule QtGui
Definition qevent.h:195
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:485
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
\inmodule QtCore\reentrant
Definition qpoint.h:214
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:499
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
bool contains(const QRectF &r) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:1985
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:799
bool intersects(const QRectF &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e.
Definition qrect.cpp:2263
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:497
QRectF united(const QRectF &other) const noexcept
Definition qrect.h:838
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:321
\inmodule QtCore
Definition qstack.h:13
\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:76
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
void _q_activateAnchor(const QString &href)
QUrl resolveUrl(const QString &url) const
QTextDocument::ResourceType currentType
void restoreHistoryEntry(const HistoryEntry &entry)
void _q_highlightLink(const QString &href)
void emitHighlighted(const QUrl &url)
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.
QString anchorHref() const
Returns the text format's hypertext link, or an empty string if none has been set.
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
ResourceType
This enum describes the types of resources that can be loaded by QTextDocument's loadResource() funct...
QWidgetTextControl * control
Definition qtextedit_p.h:79
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
bool isReadOnly() const
Qt::TextInteractionFlags textInteractionFlags
Definition qtextedit.h:50
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:3354
QString fragment(ComponentFormattingOptions options=PrettyDecoded) const
Returns the fragment of the URL.
Definition qurl.cpp:2679
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2494
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2722
void setFragment(const QString &fragment, ParsingMode mode=TolerantMode)
Sets the fragment of the URL to fragment.
Definition qurl.cpp:2645
bool hasFragment() const
Definition qurl.cpp:2697
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2797
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
QUrl adjusted(FormattingOptions options) const
Definition qurl.cpp:2921
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
@ RemoveFilename
Definition qurl.h:116
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3411
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
\inmodule QtCore
Definition qvariant.h:64
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)
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
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
double e
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ TextSelectableByMouse
@ TextEditable
@ TextBrowserInteraction
@ WA_InputMethodEnabled
Definition qnamespace.h:294
@ PointingHandCursor
@ WaitCursor
@ IBeamCursor
@ Key_Select
@ Key_Right
Definition qnamespace.h:674
@ Key_Left
Definition qnamespace.h:672
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
@ Key_Back
Definition qnamespace.h:841
@ AltModifier
#define Q_UNLIKELY(x)
#define qWarning
Definition qlogging.h:162
#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
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLint GLsizei GLsizei height
GLfloat GLfloat f
GLenum type
GLsizei const GLuint * paths
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLuint entry
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
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:145
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
QByteArray ba
[0]
file open(QIODevice::ReadOnly)
QFileInfo fi("c:/temp/foo")
[newstuff]
QUrl url("example.com")
[constructor-url-reference]
QUrl baseUrl
Text files * txt
view viewport() -> scroll(dx, dy, deviceRect)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent