diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-05-25 12:09:53 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-06-20 20:29:15 +0200 |
commit | b149f5d77a3c362af1e82e95ddf0ae13954d2538 (patch) | |
tree | 8a668cffd0844dc91de222047135066f82e6ace0 | |
parent | 84536ae61ed887f179deafb75fd28757f1cf9aba (diff) |
Overload QTextBrowser::setSource() to add optional type argument
Now that it's trying to guess whether the type is markdown based on
the file extension, there needs to be a way to override it. For example
it might be arranged that directory listings will be generated in
markdown format instead of HTML; then when loading a source URL that
is a directory, the application may override the type. The type for
the single-argument setSource(url) is UnknownResource to preserve
the existing behavior, but the user can override the guessing by
setting a specific type.
Change-Id: Id111efd24de7d8fd18c47b16a2d58f5b09d77891
Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
-rw-r--r-- | src/gui/text/qtextdocument.h | 2 | ||||
-rw-r--r-- | src/widgets/widgets/qtextbrowser.cpp | 84 | ||||
-rw-r--r-- | src/widgets/widgets/qtextbrowser.h | 11 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qtextbrowser/heading.html | 2 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qtextbrowser/markdown.really | 2 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro | 2 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp | 45 |
7 files changed, 127 insertions, 21 deletions
diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index edb6bd9310..2fadc40cd2 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -225,6 +225,7 @@ public: void print(QPagedPaintDevice *printer) const; enum ResourceType { + UnknownResource = 0, HtmlResource = 1, ImageResource = 2, StyleSheetResource = 3, @@ -232,6 +233,7 @@ public: UserResource = 100 }; + Q_ENUM(ResourceType) QVariant resource(int type, const QUrl &name) const; void addResource(int type, const QUrl &name, const QVariant &resource); diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp index 8e06efc75e..bee1021950 100644 --- a/src/widgets/widgets/qtextbrowser.cpp +++ b/src/widgets/widgets/qtextbrowser.cpp @@ -86,6 +86,7 @@ public: int hpos; int vpos; int focusIndicatorPosition, focusIndicatorAnchor; + QTextDocument::ResourceType type = QTextDocument::UnknownResource; }; HistoryEntry history(int i) const @@ -122,6 +123,8 @@ public: bool openExternalLinks; bool openLinks; + QTextDocument::ResourceType currentType; + #ifndef QT_NO_CURSOR QCursor oldCursor; #endif @@ -137,7 +140,7 @@ public: void _q_activateAnchor(const QString &href); void _q_highlightLink(const QString &href); - void setSource(const QUrl &url); + void setSource(const QUrl &url, QTextDocument::ResourceType type); // re-imlemented from QTextEditPrivate virtual QUrl resolveUrl(const QUrl &url) const override; @@ -274,7 +277,7 @@ void QTextBrowserPrivate::_q_highlightLink(const QString &anchor) } } -void QTextBrowserPrivate::setSource(const QUrl &url) +void QTextBrowserPrivate::setSource(const QUrl &url, QTextDocument::ResourceType type) { Q_Q(QTextBrowser); #ifndef QT_NO_CURSOR @@ -291,14 +294,18 @@ void QTextBrowserPrivate::setSource(const QUrl &url) currentUrlWithoutFragment.setFragment(QString()); QUrl newUrlWithoutFragment = currentURL.resolved(url); newUrlWithoutFragment.setFragment(QString()); - QTextDocument::ResourceType type = QTextDocument::HtmlResource; QString fileName = url.fileName(); + if (type == QTextDocument::UnknownResource) { #if QT_CONFIG(textmarkdownreader) - if (fileName.endsWith(QLatin1String(".md")) || - fileName.endsWith(QLatin1String(".mkd")) || - fileName.endsWith(QLatin1String(".markdown"))) - type = QTextDocument::MarkdownResource; + if (fileName.endsWith(QLatin1String(".md")) || + fileName.endsWith(QLatin1String(".mkd")) || + fileName.endsWith(QLatin1String(".markdown"))) + type = QTextDocument::MarkdownResource; + else #endif + type = QTextDocument::HtmlResource; + } + currentType = type; if (url.isValid() && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) { @@ -574,6 +581,7 @@ QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() cons { HistoryEntry entry; entry.url = q_func()->source(); + entry.type = q_func()->sourceType(); entry.title = q_func()->documentTitle(); entry.hpos = hbar->value(); entry.vpos = vbar->value(); @@ -590,7 +598,7 @@ QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() cons void QTextBrowserPrivate::restoreHistoryEntry(const HistoryEntry &entry) { - setSource(entry.url); + setSource(entry.url, entry.type); hbar->setValue(entry.hpos); vbar->setValue(entry.vpos); if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) { @@ -732,7 +740,13 @@ QTextBrowser::~QTextBrowser() document is displayed as a popup rather than as new document in the browser window itself. Otherwise, the document is displayed normally in the text browser with the text set to the contents of - the named document with setHtml(). + the named document with \l QTextDocument::setHtml() or + \l QTextDocument::setMarkdown(), depending on whether the filename ends + with any of the known Markdown file extensions. + + If you would like to avoid automatic type detection + and specify the type explicitly, call setSource() rather than + setting this property. By default, this property contains an empty URL. */ @@ -746,6 +760,23 @@ QUrl QTextBrowser::source() const } /*! + \property QTextBrowser::sourceType + \brief the type of the displayed document + + This is QTextDocument::UnknownResource if no document is displayed or if + the type of the source is unknown. Otherwise it holds the type that was + detected, or the type that was specified when setSource() was called. +*/ +QTextDocument::ResourceType QTextBrowser::sourceType() const +{ + Q_D(const QTextBrowser); + if (d->stack.isEmpty()) + return QTextDocument::UnknownResource; + else + return d->stack.top().type; +} + +/*! \property QTextBrowser::searchPaths \brief the search paths used by the text browser to find supporting content @@ -775,16 +806,46 @@ void QTextBrowser::reload() Q_D(QTextBrowser); QUrl s = d->currentURL; d->currentURL = QUrl(); - setSource(s); + setSource(s, d->currentType); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void QTextBrowser::setSource(const QUrl &url) { + setSource(url, QTextDocument::UnknownResource); +} +#endif + +/*! + Attempts to load the document at the given \a url with the specified \a type. + + If \a type is \l {QTextDocument::ResourceType::UnknownResource}{UnknownResource} + (the default), the document type will be detected: that is, if the url ends + with an extension of \c{.md}, \c{.mkd} or \c{.markdown}, the document will be + loaded via \l QTextDocument::setMarkdown(); otherwise it will be loaded via + \l QTextDocument::setHtml(). This detection can be bypassed by specifying + the \a type explicitly. +*/ +void QTextBrowser::setSource(const QUrl &url, QTextDocument::ResourceType type) +{ + doSetSource(url, type); +} + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +/*! + Attempts to load the document at the given \a url with the specified \a type. + + setSource() calls doSetSource. In Qt 5, setSource(const QUrl &url) was virtual. + In Qt 6, doSetSource() is virtual instead, so that it can be overridden in subclasses. +*/ +#endif +void QTextBrowser::doSetSource(const QUrl &url, QTextDocument::ResourceType type) +{ Q_D(QTextBrowser); const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry(); - d->setSource(url); + d->setSource(url, type); if (!url.isValid()) return; @@ -798,6 +859,7 @@ void QTextBrowser::setSource(const QUrl &url) QTextBrowserPrivate::HistoryEntry entry; entry.url = url; + entry.type = d->currentType; entry.title = documentTitle(); entry.hpos = 0; entry.vpos = 0; diff --git a/src/widgets/widgets/qtextbrowser.h b/src/widgets/widgets/qtextbrowser.h index ea81256f50..33e5b3980c 100644 --- a/src/widgets/widgets/qtextbrowser.h +++ b/src/widgets/widgets/qtextbrowser.h @@ -55,6 +55,7 @@ class Q_WIDGETS_EXPORT QTextBrowser : public QTextEdit Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource) + Q_PROPERTY(QTextDocument::ResourceType sourceType READ sourceType) Q_OVERRIDE(bool modified SCRIPTABLE false) Q_OVERRIDE(bool readOnly DESIGNABLE false SCRIPTABLE false) Q_OVERRIDE(bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false) @@ -67,6 +68,7 @@ public: virtual ~QTextBrowser(); QUrl source() const; + QTextDocument::ResourceType sourceType() const; QStringList searchPaths() const; void setSearchPaths(const QStringList &paths); @@ -88,7 +90,12 @@ public: void setOpenLinks(bool open); public Q_SLOTS: +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) virtual void setSource(const QUrl &name); + void setSource(const QUrl &name, QTextDocument::ResourceType type); +#else + void setSource(const QUrl &name, QTextDocument::ResourceType type = QTextDocument::UnknownResource); +#endif virtual void backward(); virtual void forward(); virtual void home(); @@ -112,6 +119,10 @@ protected: virtual void focusOutEvent(QFocusEvent *ev) override; virtual bool focusNextPrevChild(bool next) override; virtual void paintEvent(QPaintEvent *e) override; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + virtual +#endif + void doSetSource(const QUrl &name, QTextDocument::ResourceType type = QTextDocument::UnknownResource); private: Q_DISABLE_COPY(QTextBrowser) diff --git a/tests/auto/widgets/widgets/qtextbrowser/heading.html b/tests/auto/widgets/widgets/qtextbrowser/heading.html new file mode 100644 index 0000000000..8b23807f65 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/heading.html @@ -0,0 +1,2 @@ +<h3>this is a heading</h3> +<p>this is a paragraph</p> diff --git a/tests/auto/widgets/widgets/qtextbrowser/markdown.really b/tests/auto/widgets/widgets/qtextbrowser/markdown.really new file mode 100644 index 0000000000..be56aef234 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/markdown.really @@ -0,0 +1,2 @@ +### this is a heading +this is a paragraph diff --git a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro index 05c156bf59..dfdcf26497 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro +++ b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro @@ -4,6 +4,6 @@ SOURCES += tst_qtextbrowser.cpp QT += widgets testlib -TESTDATA += *.html *.md subdir/* +TESTDATA += *.html *.md markdown.really subdir/* builtin_testdata: DEFINES += BUILTIN_TESTDATA diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp index 22cd3b46c6..083e297941 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp +++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp @@ -92,7 +92,8 @@ private slots: void focusIndicator(); void focusHistory(); void urlEncoding(); - void markdown(); + void sourceType_data(); + void sourceType(); private: TestBrowser *browser; @@ -679,19 +680,45 @@ void tst_QTextBrowser::urlEncoding() delete browser; } -void tst_QTextBrowser::markdown() +void tst_QTextBrowser::sourceType_data() { - browser->setSource(QUrl::fromLocalFile(QFINDTESTDATA("markdown.md"))); + QTest::addColumn<QString>("sourceFile"); + QTest::addColumn<QTextDocument::ResourceType>("sourceType"); + QTest::addColumn<int>("expectedMaxHeadingLevel"); + QTest::addColumn<QTextDocument::ResourceType>("expectedSourceType"); + +#if QT_CONFIG(textmarkdownreader) + const int maxMdHeadingLevel = 3; + const QTextDocument::ResourceType mdExpectedType = QTextDocument::MarkdownResource; +#else + // If Qt doesn't support markdown, and we read a MD document anyway, it won't have any H3's. + const int maxMdHeadingLevel = 0; + const QTextDocument::ResourceType mdExpectedType = QTextDocument::HtmlResource; +#endif + QTest::newRow("markdown detected") << "markdown.md" << QTextDocument::UnknownResource << maxMdHeadingLevel << mdExpectedType; + QTest::newRow("markdown specified") << "markdown.really" << QTextDocument::MarkdownResource << maxMdHeadingLevel << mdExpectedType; + QTest::newRow("markdown not identified") << "markdown.really" << QTextDocument::UnknownResource << 0 << QTextDocument::HtmlResource; + QTest::newRow("html detected") << "heading.html" << QTextDocument::UnknownResource << 3 << QTextDocument::HtmlResource; + QTest::newRow("html specified") << "heading.html" << QTextDocument::HtmlResource << 3 << QTextDocument::HtmlResource; +} + +void tst_QTextBrowser::sourceType() +{ + QFETCH(QString, sourceFile); + QFETCH(QTextDocument::ResourceType, sourceType); + QFETCH(int, expectedMaxHeadingLevel); + QFETCH(QTextDocument::ResourceType, expectedSourceType); + if (sourceType == QTextDocument::UnknownResource) + // verify that the property setter works, with its default parameter for sourceType + browser->setProperty("source", QUrl::fromLocalFile(QFINDTESTDATA(sourceFile))); + else + browser->setSource(QUrl::fromLocalFile(QFINDTESTDATA(sourceFile)), sourceType); + QCOMPARE(browser->sourceType(), expectedSourceType); QTextFrame::iterator iterator = browser->document()->rootFrame()->begin(); int maxHeadingLevel = -1; while (!iterator.atEnd()) maxHeadingLevel = qMax(iterator++.currentBlock().blockFormat().intProperty(QTextFormat::HeadingLevel), maxHeadingLevel); -#if QT_CONFIG(textmarkdownreader) - QCOMPARE(maxHeadingLevel, 3); -#else - // If Qt doesn't support markdown, this document will be misidentified as HTML, so it won't have any H3's. - QCOMPARE(maxHeadingLevel, 0); -#endif + QCOMPARE(maxHeadingLevel, expectedMaxHeadingLevel); } QTEST_MAIN(tst_QTextBrowser) |