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;
|
void print(QPagedPaintDevice *printer) const;
|
||||||
|
|
||||||
enum ResourceType {
|
enum ResourceType {
|
||||||
|
UnknownResource = 0,
|
||||||
HtmlResource = 1,
|
HtmlResource = 1,
|
||||||
ImageResource = 2,
|
ImageResource = 2,
|
||||||
StyleSheetResource = 3,
|
StyleSheetResource = 3,
|
||||||
@ -232,6 +233,7 @@ public:
|
|||||||
|
|
||||||
UserResource = 100
|
UserResource = 100
|
||||||
};
|
};
|
||||||
|
Q_ENUM(ResourceType)
|
||||||
|
|
||||||
QVariant resource(int type, const QUrl &name) const;
|
QVariant resource(int type, const QUrl &name) const;
|
||||||
void addResource(int type, const QUrl &name, const QVariant &resource);
|
void addResource(int type, const QUrl &name, const QVariant &resource);
|
||||||
|
@ -86,6 +86,7 @@ public:
|
|||||||
int hpos;
|
int hpos;
|
||||||
int vpos;
|
int vpos;
|
||||||
int focusIndicatorPosition, focusIndicatorAnchor;
|
int focusIndicatorPosition, focusIndicatorAnchor;
|
||||||
|
QTextDocument::ResourceType type = QTextDocument::UnknownResource;
|
||||||
};
|
};
|
||||||
|
|
||||||
HistoryEntry history(int i) const
|
HistoryEntry history(int i) const
|
||||||
@ -122,6 +123,8 @@ public:
|
|||||||
bool openExternalLinks;
|
bool openExternalLinks;
|
||||||
bool openLinks;
|
bool openLinks;
|
||||||
|
|
||||||
|
QTextDocument::ResourceType currentType;
|
||||||
|
|
||||||
#ifndef QT_NO_CURSOR
|
#ifndef QT_NO_CURSOR
|
||||||
QCursor oldCursor;
|
QCursor oldCursor;
|
||||||
#endif
|
#endif
|
||||||
@ -137,7 +140,7 @@ public:
|
|||||||
void _q_activateAnchor(const QString &href);
|
void _q_activateAnchor(const QString &href);
|
||||||
void _q_highlightLink(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
|
// re-imlemented from QTextEditPrivate
|
||||||
virtual QUrl resolveUrl(const QUrl &url) const override;
|
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);
|
Q_Q(QTextBrowser);
|
||||||
#ifndef QT_NO_CURSOR
|
#ifndef QT_NO_CURSOR
|
||||||
@ -291,14 +294,18 @@ void QTextBrowserPrivate::setSource(const QUrl &url)
|
|||||||
currentUrlWithoutFragment.setFragment(QString());
|
currentUrlWithoutFragment.setFragment(QString());
|
||||||
QUrl newUrlWithoutFragment = currentURL.resolved(url);
|
QUrl newUrlWithoutFragment = currentURL.resolved(url);
|
||||||
newUrlWithoutFragment.setFragment(QString());
|
newUrlWithoutFragment.setFragment(QString());
|
||||||
QTextDocument::ResourceType type = QTextDocument::HtmlResource;
|
|
||||||
QString fileName = url.fileName();
|
QString fileName = url.fileName();
|
||||||
|
if (type == QTextDocument::UnknownResource) {
|
||||||
#if QT_CONFIG(textmarkdownreader)
|
#if QT_CONFIG(textmarkdownreader)
|
||||||
if (fileName.endsWith(QLatin1String(".md")) ||
|
if (fileName.endsWith(QLatin1String(".md")) ||
|
||||||
fileName.endsWith(QLatin1String(".mkd")) ||
|
fileName.endsWith(QLatin1String(".mkd")) ||
|
||||||
fileName.endsWith(QLatin1String(".markdown")))
|
fileName.endsWith(QLatin1String(".markdown")))
|
||||||
type = QTextDocument::MarkdownResource;
|
type = QTextDocument::MarkdownResource;
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
type = QTextDocument::HtmlResource;
|
||||||
|
}
|
||||||
|
currentType = type;
|
||||||
|
|
||||||
if (url.isValid()
|
if (url.isValid()
|
||||||
&& (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) {
|
&& (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) {
|
||||||
@ -574,6 +581,7 @@ QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() cons
|
|||||||
{
|
{
|
||||||
HistoryEntry entry;
|
HistoryEntry entry;
|
||||||
entry.url = q_func()->source();
|
entry.url = q_func()->source();
|
||||||
|
entry.type = q_func()->sourceType();
|
||||||
entry.title = q_func()->documentTitle();
|
entry.title = q_func()->documentTitle();
|
||||||
entry.hpos = hbar->value();
|
entry.hpos = hbar->value();
|
||||||
entry.vpos = vbar->value();
|
entry.vpos = vbar->value();
|
||||||
@ -590,7 +598,7 @@ QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() cons
|
|||||||
|
|
||||||
void QTextBrowserPrivate::restoreHistoryEntry(const HistoryEntry &entry)
|
void QTextBrowserPrivate::restoreHistoryEntry(const HistoryEntry &entry)
|
||||||
{
|
{
|
||||||
setSource(entry.url);
|
setSource(entry.url, entry.type);
|
||||||
hbar->setValue(entry.hpos);
|
hbar->setValue(entry.hpos);
|
||||||
vbar->setValue(entry.vpos);
|
vbar->setValue(entry.vpos);
|
||||||
if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) {
|
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
|
document is displayed as a popup rather than as new document in
|
||||||
the browser window itself. Otherwise, the document is displayed
|
the browser window itself. Otherwise, the document is displayed
|
||||||
normally in the text browser with the text set to the contents of
|
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.
|
By default, this property contains an empty URL.
|
||||||
*/
|
*/
|
||||||
@ -745,6 +759,23 @@ QUrl QTextBrowser::source() const
|
|||||||
return d->stack.top().url;
|
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
|
\property QTextBrowser::searchPaths
|
||||||
\brief the search paths used by the text browser to find supporting
|
\brief the search paths used by the text browser to find supporting
|
||||||
@ -775,16 +806,46 @@ void QTextBrowser::reload()
|
|||||||
Q_D(QTextBrowser);
|
Q_D(QTextBrowser);
|
||||||
QUrl s = d->currentURL;
|
QUrl s = d->currentURL;
|
||||||
d->currentURL = QUrl();
|
d->currentURL = QUrl();
|
||||||
setSource(s);
|
setSource(s, d->currentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||||
void QTextBrowser::setSource(const QUrl &url)
|
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);
|
Q_D(QTextBrowser);
|
||||||
|
|
||||||
const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry();
|
const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry();
|
||||||
|
|
||||||
d->setSource(url);
|
d->setSource(url, type);
|
||||||
|
|
||||||
if (!url.isValid())
|
if (!url.isValid())
|
||||||
return;
|
return;
|
||||||
@ -798,6 +859,7 @@ void QTextBrowser::setSource(const QUrl &url)
|
|||||||
|
|
||||||
QTextBrowserPrivate::HistoryEntry entry;
|
QTextBrowserPrivate::HistoryEntry entry;
|
||||||
entry.url = url;
|
entry.url = url;
|
||||||
|
entry.type = d->currentType;
|
||||||
entry.title = documentTitle();
|
entry.title = documentTitle();
|
||||||
entry.hpos = 0;
|
entry.hpos = 0;
|
||||||
entry.vpos = 0;
|
entry.vpos = 0;
|
||||||
|
@ -55,6 +55,7 @@ class Q_WIDGETS_EXPORT QTextBrowser : public QTextEdit
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QUrl source READ source WRITE setSource)
|
Q_PROPERTY(QUrl source READ source WRITE setSource)
|
||||||
|
Q_PROPERTY(QTextDocument::ResourceType sourceType READ sourceType)
|
||||||
Q_OVERRIDE(bool modified SCRIPTABLE false)
|
Q_OVERRIDE(bool modified SCRIPTABLE false)
|
||||||
Q_OVERRIDE(bool readOnly DESIGNABLE false SCRIPTABLE false)
|
Q_OVERRIDE(bool readOnly DESIGNABLE false SCRIPTABLE false)
|
||||||
Q_OVERRIDE(bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false)
|
Q_OVERRIDE(bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false)
|
||||||
@ -67,6 +68,7 @@ public:
|
|||||||
virtual ~QTextBrowser();
|
virtual ~QTextBrowser();
|
||||||
|
|
||||||
QUrl source() const;
|
QUrl source() const;
|
||||||
|
QTextDocument::ResourceType sourceType() const;
|
||||||
|
|
||||||
QStringList searchPaths() const;
|
QStringList searchPaths() const;
|
||||||
void setSearchPaths(const QStringList &paths);
|
void setSearchPaths(const QStringList &paths);
|
||||||
@ -88,7 +90,12 @@ public:
|
|||||||
void setOpenLinks(bool open);
|
void setOpenLinks(bool open);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||||
virtual void setSource(const QUrl &name);
|
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 backward();
|
||||||
virtual void forward();
|
virtual void forward();
|
||||||
virtual void home();
|
virtual void home();
|
||||||
@ -112,6 +119,10 @@ protected:
|
|||||||
virtual void focusOutEvent(QFocusEvent *ev) override;
|
virtual void focusOutEvent(QFocusEvent *ev) override;
|
||||||
virtual bool focusNextPrevChild(bool next) override;
|
virtual bool focusNextPrevChild(bool next) override;
|
||||||
virtual void paintEvent(QPaintEvent *e) 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:
|
private:
|
||||||
Q_DISABLE_COPY(QTextBrowser)
|
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
|
QT += widgets testlib
|
||||||
|
|
||||||
TESTDATA += *.html *.md subdir/*
|
TESTDATA += *.html *.md markdown.really subdir/*
|
||||||
|
|
||||||
builtin_testdata: DEFINES += BUILTIN_TESTDATA
|
builtin_testdata: DEFINES += BUILTIN_TESTDATA
|
||||||
|
@ -92,7 +92,8 @@ private slots:
|
|||||||
void focusIndicator();
|
void focusIndicator();
|
||||||
void focusHistory();
|
void focusHistory();
|
||||||
void urlEncoding();
|
void urlEncoding();
|
||||||
void markdown();
|
void sourceType_data();
|
||||||
|
void sourceType();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TestBrowser *browser;
|
TestBrowser *browser;
|
||||||
@ -679,19 +680,45 @@ void tst_QTextBrowser::urlEncoding()
|
|||||||
delete browser;
|
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();
|
QTextFrame::iterator iterator = browser->document()->rootFrame()->begin();
|
||||||
int maxHeadingLevel = -1;
|
int maxHeadingLevel = -1;
|
||||||
while (!iterator.atEnd())
|
while (!iterator.atEnd())
|
||||||
maxHeadingLevel = qMax(iterator++.currentBlock().blockFormat().intProperty(QTextFormat::HeadingLevel), maxHeadingLevel);
|
maxHeadingLevel = qMax(iterator++.currentBlock().blockFormat().intProperty(QTextFormat::HeadingLevel), maxHeadingLevel);
|
||||||
#if QT_CONFIG(textmarkdownreader)
|
QCOMPARE(maxHeadingLevel, expectedMaxHeadingLevel);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QTextBrowser)
|
QTEST_MAIN(tst_QTextBrowser)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user