ExtensionManager: Interpret description text as MarkDown

Task-number: QTCREATORBUG-31199
Fixes: QTCREATORBUG-31182
Change-Id: Iff0ec94db67b3afcad024b2fec4797805f1123e8
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Alessandro Portale
2024-07-17 13:12:29 +02:00
parent 3fd60717eb
commit 3ea8c7808e

View File

@@ -46,6 +46,8 @@
#include <QProgressDialog> #include <QProgressDialog>
#include <QScrollArea> #include <QScrollArea>
#include <QSignalMapper> #include <QSignalMapper>
#include <QTextDocument>
#include <QTextBlock>
using namespace Core; using namespace Core;
using namespace Utils; using namespace Utils;
@@ -421,8 +423,9 @@ ExtensionManagerWidget::ExtensionManagerWidget()
m_secondaryDescriptionWidget = new CollapsingWidget; m_secondaryDescriptionWidget = new CollapsingWidget;
m_headingWidget = new HeadingWidget; m_headingWidget = new HeadingWidget;
m_description = tfLabel(contentTF, false); m_description = new QLabel;
m_description->setWordWrap(true); m_description->setWordWrap(true);
m_description->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information"));
m_links = tfLabel(contentTF, false); m_links = tfLabel(contentTF, false);
m_links->setOpenExternalLinks(true); m_links->setOpenExternalLinks(true);
@@ -528,6 +531,47 @@ ExtensionManagerWidget::ExtensionManagerWidget()
updateView({}); updateView({});
} }
static QString markdownToHtml(const QString &markdown)
{
QTextDocument doc;
doc.setMarkdown(markdown);
doc.setDefaultFont(contentTF.font());
for (QTextBlock block = doc.begin(); block != doc.end(); block = block.next()) {
QTextBlockFormat blockFormat = block.blockFormat();
if (blockFormat.hasProperty(QTextFormat::HeadingLevel))
blockFormat.setTopMargin(SpacingTokens::ExVPaddingGapXl);
else
blockFormat.setLineHeight(contentTF.lineHeight(), QTextBlockFormat::FixedHeight);
blockFormat.setBottomMargin(SpacingTokens::VGapL);
QTextCursor cursor(block);
cursor.mergeBlockFormat(blockFormat);
const TextFormat headingTf = blockFormat.headingLevel() == 1 ? h5TF : h6TF;
const QFont headingFont = headingTf.font();
for (auto it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment fragment = it.fragment();
if (fragment.isValid()) {
QTextCharFormat charFormat = fragment.charFormat();
cursor.setPosition(fragment.position());
cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
if (blockFormat.hasProperty(QTextFormat::HeadingLevel)) {
charFormat.setFontFamilies(headingFont.families());
charFormat.setFontWeight(headingFont.weight());
charFormat.setFontPointSize(headingFont.pointSizeF());
charFormat.setForeground(headingTf.color());
} else if (charFormat.isAnchor()) {
charFormat.setForeground(creatorColor(Theme::Token_Text_Accent));
} else {
charFormat.setForeground(contentTF.color());
}
cursor.setCharFormat(charFormat);
}
}
}
return doc.toHtml();
}
void ExtensionManagerWidget::updateView(const QModelIndex &current) void ExtensionManagerWidget::updateView(const QModelIndex &current)
{ {
m_headingWidget->update(current); m_headingWidget->update(current);
@@ -556,28 +600,15 @@ void ExtensionManagerWidget::updateView(const QModelIndex &current)
const TextData textData = current.data(RoleDescriptionText).value<TextData>(); const TextData textData = current.data(RoleDescriptionText).value<TextData>();
const bool hasDescription = !textData.isEmpty(); const bool hasDescription = !textData.isEmpty();
if (hasDescription) { if (hasDescription) {
const QString headerCssTemplate = QString descriptionMarkdown;
";margin-top:%1;margin-bottom:%2;padding-top:0;padding-bottom:0;";
const QString h4Css = fontToCssProperties(uiFont(UiElementH4))
+ headerCssTemplate.arg(0).arg(SpacingTokens::VGapL);
const QString h5Css = fontToCssProperties(uiFont(UiElementH5))
+ headerCssTemplate.arg(SpacingTokens::ExVPaddingGapXl)
.arg(SpacingTokens::VGapL);
QString descriptionHtml;
for (const TextData::Type &text : textData) { for (const TextData::Type &text : textData) {
if (text.second.isEmpty()) if (!text.first.isEmpty()) {
continue; const QLatin1String headingMark(descriptionMarkdown.isEmpty() ? "#" : "\n\n##");
const QString paragraph = descriptionMarkdown.append(headingMark + " " + text.first + "\n");
QString::fromLatin1("<div style=\"%1\">%2</div>%3") }
.arg(descriptionHtml.isEmpty() ? h4Css : h5Css) descriptionMarkdown.append(text.second.join("\n"));
.arg(text.first)
.arg(toContentParagraph(text.second.join("<br/>")));
descriptionHtml.append(paragraph);
} }
descriptionHtml.prepend(QString::fromLatin1("<body style=\"color:%1;\">") m_description->setText(markdownToHtml(descriptionMarkdown));
.arg(creatorColor(Theme::Token_Text_Default).name()));
descriptionHtml.append("</body>");
m_description->setText(descriptionHtml);
} }
m_description->setVisible(hasDescription); m_description->setVisible(hasDescription);