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>
This commit is contained in:
parent
84536ae61e
commit
b149f5d77a
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -745,6 +759,23 @@ QUrl QTextBrowser::source() const
|
||||
return d->stack.top().url;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
@ -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;
|
||||
|
@ -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)
|
||||
|
2
tests/auto/widgets/widgets/qtextbrowser/heading.html
Normal file
2
tests/auto/widgets/widgets/qtextbrowser/heading.html
Normal file
@ -0,0 +1,2 @@
|
||||
<h3>this is a heading</h3>
|
||||
<p>this is a paragraph</p>
|
2
tests/auto/widgets/widgets/qtextbrowser/markdown.really
Normal file
2
tests/auto/widgets/widgets/qtextbrowser/markdown.really
Normal file
@ -0,0 +1,2 @@
|
||||
### this is a heading
|
||||
this is a paragraph
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user