From 56f0ebfe860e440dcbba8997f44836debc901119 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 20 May 2022 09:23:28 +0200 Subject: Support markdown in QTextEditMimeData; fix pasting trailing newlines - Since 4edcea762d9ce334c4c1a78234c90c118b81da87 the dropsite example shows markdown if available; and now it shows that when we do DnD of a selection from the richtext example, text/markdown is available. - If we artificially make html unavailable, copying and pasting between widget-based rich text editors uses markdown. In case markdown writer output contains unnecessary backticks due to monospace fonts getting used, the workaround from 1ad456c908467212bc30223a69eb7524b64b86e1 is applied. Pick-to: 6.4 Task-number: QTBUG-76105 Task-number: QTBUG-103484 Change-Id: Ie6ca4dbb450dbc36b3d09fd0df1ae5909aaebca7 Reviewed-by: Qt CI Bot Reviewed-by: Allan Sandfeld Jensen --- .../corelib/kernel/qmimedata/tst_qmimedata.cpp | 11 +++ .../widgets/widgets/qtextedit/tst_qtextedit.cpp | 94 ++++++++++++++++++++++ 2 files changed, 105 insertions(+) (limited to 'tests') diff --git a/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp b/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp index 16d5c5308e..03b07c41ec 100644 --- a/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp +++ b/tests/auto/corelib/kernel/qmimedata/tst_qmimedata.cpp @@ -72,12 +72,19 @@ void tst_QMimeData::data() const mimeData.setData("text/plain", "pirates"); QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates")); QCOMPARE(mimeData.data("text/html").length(), 0); + QCOMPARE(mimeData.data("text/markdown").length(), 0); // html time mimeData.setData("text/html", "ninjas"); QCOMPARE(mimeData.data("text/html"), QByteArray("ninjas")); QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates")); // make sure text not damaged QCOMPARE(mimeData.data("text/html"), mimeData.html().toLatin1()); + + // markdown time + mimeData.setData("text/markdown", "vikings"); + QCOMPARE(mimeData.data("text/markdown"), QByteArray("vikings")); + QCOMPARE(mimeData.data("text/html"), QByteArray("ninjas")); + QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates")); } void tst_QMimeData::formats() const @@ -92,6 +99,10 @@ void tst_QMimeData::formats() const mimeData.setData("text/html", "ninjas"); QCOMPARE(mimeData.formats(), QStringList() << "text/plain" << "text/html"); + // set markdown, verify + mimeData.setData("text/markdown", "vikings"); + QCOMPARE(mimeData.formats(), QStringList() << "text/plain" << "text/html" << "text/markdown"); + // clear, verify mimeData.clear(); QCOMPARE(mimeData.formats(), QStringList()); diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp index dbcc4c32e3..ff5d3ab083 100644 --- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp @@ -114,7 +114,13 @@ private slots: void moveCursor(); #ifndef QT_NO_CLIPBOARD void mimeDataReimplementations(); +#ifndef QT_NO_TEXTHTMLPARSER + void mimeTypesAvailableFromRichText(); #endif +#if QT_CONFIG(textmarkdownreader) + void mimeTypesAvailableFromMarkdown(); +#endif +#endif // QT_NO_CLIPBOARD void ctrlEnterShouldInsertLineSeparator_NOT(); void shiftEnterShouldInsertLineSeparator(); void selectWordsFromStringsContainingSeparators_data(); @@ -150,6 +156,7 @@ private slots: void setDocumentPreservesPalette(); #endif void pasteFromQt3RichText(); + void pasteFromMarkdown(); void noWrapBackgrounds(); void preserveCharFormatAfterUnchangingSetPosition(); void twoSameInputMethodEvents(); @@ -193,6 +200,7 @@ private: void createSelection(); int blockCount() const; void compareWidgetAndImage(QTextEdit &widget, const QString &imageFileName); + bool isMainFontFixed(); QTextEdit *ed; qreal rootFrameMargin; @@ -1480,7 +1488,63 @@ void tst_QTextEdit::mimeDataReimplementations() QCOMPARE(ed.insertCallCount, 1); #endif } + +#ifndef QT_NO_TEXTHTMLPARSER +void tst_QTextEdit::mimeTypesAvailableFromRichText() +{ + MyTextEdit ed; + ed.setHtml("Hello World"); + ed.selectAll(); + ed.copy(); + const auto *mimeData = QApplication::clipboard()->mimeData(); + qCDebug(lcTests) << "available mime types" << mimeData->formats(); + QVERIFY(mimeData->formats().contains("text/plain")); +#if QT_CONFIG(textmarkdownwriter) + QVERIFY(mimeData->formats().contains("text/markdown")); + const QByteArray expectedMarkdown = "*Hello **World***\n\n"; + if (mimeData->data("text/markdown") != expectedMarkdown && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(mimeData->data("text/markdown"), expectedMarkdown); +#endif +#ifndef QT_NO_TEXTHTMLPARSER + QVERIFY(mimeData->formats().contains("text/html")); + QVERIFY(mimeData->hasHtml()); +#endif +#ifndef QT_NO_TEXTODFWRITER + QVERIFY(mimeData->formats().contains("application/vnd.oasis.opendocument.text")); +#endif +} +#endif // QT_NO_TEXTHTMLPARSER + +#if QT_CONFIG(textmarkdownreader) +void tst_QTextEdit::mimeTypesAvailableFromMarkdown() +{ + MyTextEdit ed; + const QString md("# TODO\n\n- [x] Fix bugs\n- [ ] Have a beer\n"); + ed.setMarkdown(md); + ed.selectAll(); + ed.copy(); + const auto *mimeData = QApplication::clipboard()->mimeData(); + qCDebug(lcTests) << "available mime types" << mimeData->formats(); + QVERIFY(mimeData->formats().contains("text/plain")); +#if QT_CONFIG(textmarkdownwriter) + QVERIFY(mimeData->formats().contains("text/markdown")); + if (mimeData->data("text/markdown") != md && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(mimeData->data("text/markdown"), md); +#endif +#ifndef QT_NO_TEXTHTMLPARSER + QVERIFY(mimeData->formats().contains("text/html")); + QVERIFY(mimeData->hasHtml()); + QVERIFY(mimeData->html().contains("checked")); //
  • formats().contains("application/vnd.oasis.opendocument.text")); +#endif +} +#endif // textmarkdownreader + +#endif // QT_NO_CLIPBOARD void tst_QTextEdit::ctrlEnterShouldInsertLineSeparator_NOT() { @@ -2133,6 +2197,18 @@ void tst_QTextEdit::compareWidgetAndImage(QTextEdit &widget, const QString &imag } } +bool tst_QTextEdit::isMainFontFixed() +{ + bool ret = QFontInfo(QGuiApplication::font()).fixedPitch(); + if (ret) { + qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks"; + qCWarning(lcTests) << "system fonts: fixed" << QFontDatabase::systemFont(QFontDatabase::FixedFont) + << "fixed?" << QFontInfo(QFontDatabase::systemFont(QFontDatabase::FixedFont)).fixedPitch() + << "general" << QFontDatabase::systemFont(QFontDatabase::GeneralFont); + } + return ret; +} + void tst_QTextEdit::cursorRect() { ed->show(); @@ -2199,6 +2275,24 @@ void tst_QTextEdit::pasteFromQt3RichText() QCOMPARE(ed->toPlainText(), QString::fromLatin1(" QTextEdit is an ")); } +void tst_QTextEdit::pasteFromMarkdown() +{ + QByteArray richtext("*This* text is **rich**"); + + QMimeData mimeData; + mimeData.setData("text/markdown", richtext); + + static_cast(ed)->publicInsertFromMimeData(&mimeData); + + QCOMPARE(ed->toPlainText(), "This text is rich"); +#if QT_CONFIG(textmarkdownwriter) + const auto expectedMarkdown = QString::fromLatin1(richtext + "\n\n"); + if (ed->toMarkdown() != expectedMarkdown && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(ed->toMarkdown(), expectedMarkdown); +#endif +} + void tst_QTextEdit::noWrapBackgrounds() { QWidget topLevel; -- cgit v1.2.3