diff --git a/src/plugins/extensionmanager/extensionmanager_test.qrc b/src/plugins/extensionmanager/extensionmanager_test.qrc
index e7e934e5316..4c4d59f002d 100644
--- a/src/plugins/extensionmanager/extensionmanager_test.qrc
+++ b/src/plugins/extensionmanager/extensionmanager_test.qrc
@@ -1,8 +1,6 @@
- testdata/augmentedplugindata.json
testdata/defaultpacks.json
testdata/thirdpartyplugins.json
- testdata/varieddata.json
diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp
index f2f0f0446fd..fbfa59098db 100644
--- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp
+++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp
@@ -57,14 +57,14 @@ namespace ExtensionManager::Internal {
Q_LOGGING_CATEGORY(widgetLog, "qtc.extensionmanager.widget", QtWarningMsg)
-constexpr TextFormat h5TF
- {Theme::Token_Text_Default, UiElement::UiElementH5};
-constexpr TextFormat h6TF
- {h5TF.themeColor, UiElement::UiElementH6};
-constexpr TextFormat h6CapitalTF
- {Theme::Token_Text_Muted, UiElement::UiElementH6Capital};
constexpr TextFormat contentTF
{Theme::Token_Text_Default, UiElement::UiElementBody2};
+constexpr TextFormat h5TF
+ {contentTF.themeColor, UiElement::UiElementH5};
+constexpr TextFormat h6TF
+ {contentTF.themeColor, UiElement::UiElementH6};
+constexpr TextFormat h6CapitalTF
+ {Theme::Token_Text_Muted, UiElement::UiElementH6Capital};
static QLabel *sectionTitle(const TextFormat &tf, const QString &title)
{
@@ -215,9 +215,9 @@ public:
m_dlCount->setText(QString::number(dlCount));
m_dlCountItems->setVisible(showDlCount);
- const auto pluginData = current.data(RolePlugins).value();
+ const QStringList plugins = current.data(RolePlugins).toStringList();
if (current.data(RoleItemType).toInt() == ItemTypePack) {
- const int pluginsCount = pluginData.count();
+ const int pluginsCount = plugins.count();
const QString details = Tr::tr("Pack contains %n plugins.", nullptr, pluginsCount);
m_details->setText(details);
} else {
@@ -227,9 +227,10 @@ public:
const ItemType itemType = current.data(RoleItemType).value();
const bool isPack = itemType == ItemTypePack;
const bool isRemotePlugin = !(isPack || pluginSpecForId(current.data(RoleId).toString()));
- installButton->setVisible(isRemotePlugin && !pluginData.empty());
+ const QString downloadUrl = current.data(RoleDownloadUrl).toString();
+ installButton->setVisible(isRemotePlugin && !downloadUrl.isEmpty());
if (installButton->isVisible())
- installButton->setToolTip(pluginData.constFirst().second);
+ installButton->setToolTip(downloadUrl);
}
signals:
@@ -383,25 +384,17 @@ public:
private:
void updateView(const QModelIndex ¤t);
void fetchAndInstallPlugin(const QUrl &url);
- void fetchAndDisplayImage(const QUrl &url);
QString m_currentItemName;
+ ExtensionsModel *m_extensionModel;
ExtensionsBrowser *m_extensionBrowser;
CollapsingWidget *m_secondaryDescriptionWidget;
HeadingWidget *m_headingWidget;
QWidget *m_primaryContent;
QWidget *m_secondaryContent;
QLabel *m_description;
- QLabel *m_linksTitle;
- QLabel *m_links;
- QLabel *m_imageTitle;
- QLabel *m_image;
- QBuffer m_imageDataBuffer;
- QMovie m_imageMovie;
QLabel *m_tagsTitle;
TagList *m_tags;
- QLabel *m_compatVersionTitle;
- QLabel *m_compatVersion;
QLabel *m_platformsTitle;
QLabel *m_platforms;
QLabel *m_dependenciesTitle;
@@ -409,14 +402,14 @@ private:
QLabel *m_packExtensionsTitle;
QLabel *m_packExtensions;
PluginStatusWidget *m_pluginStatus;
- PluginsData m_currentItemPlugins;
+ QString m_currentDownloadUrl;
Tasking::TaskTreeRunner m_dlTaskTreeRunner;
- Tasking::TaskTreeRunner m_imgTaskTreeRunner;
};
ExtensionManagerWidget::ExtensionManagerWidget()
{
- m_extensionBrowser = new ExtensionsBrowser;
+ m_extensionModel = new ExtensionsModel(this);
+ m_extensionBrowser = new ExtensionsBrowser(m_extensionModel);
auto descriptionColumns = new QWidget;
m_secondaryDescriptionWidget = new CollapsingWidget;
@@ -425,21 +418,12 @@ ExtensionManagerWidget::ExtensionManagerWidget()
m_description->setWordWrap(true);
m_description->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_description->setOpenExternalLinks(true);
- m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information"));
- m_links = tfLabel(contentTF, false);
- m_links->setOpenExternalLinks(true);
- m_links->setTextInteractionFlags(Qt::TextBrowserInteraction);
- m_imageTitle = sectionTitle(h6CapitalTF, {});
- m_image = new QLabel;
- m_imageMovie.setDevice(&m_imageDataBuffer);
using namespace Layouting;
auto primary = new QWidget;
const auto spL = spacing(SpacingTokens::VPaddingL);
Column {
m_description,
- Column { m_linksTitle, m_links, spL },
- Column { m_imageTitle, m_image, spL },
st,
noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
}.attachTo(primary);
@@ -447,8 +431,6 @@ ExtensionManagerWidget::ExtensionManagerWidget()
m_tagsTitle = sectionTitle(h6TF, Tr::tr("Tags"));
m_tags = new TagList;
- m_compatVersionTitle = sectionTitle(h6TF, Tr::tr("Compatibility"));
- m_compatVersion = tfLabel(contentTF, false);
m_platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms"));
m_platforms = tfLabel(contentTF, false);
m_dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies"));
@@ -463,7 +445,6 @@ ExtensionManagerWidget::ExtensionManagerWidget()
sectionTitle(h6CapitalTF, Tr::tr("Extension details")),
Column {
Column { m_tagsTitle, m_tags, spXxs },
- Column { m_compatVersionTitle, m_compatVersion, spXxs },
Column { m_platformsTitle, m_platforms, spXxs },
Column { m_dependenciesTitle, m_dependencies, spXxs },
Column { m_packExtensionsTitle, m_packExtensions, spXxs },
@@ -522,7 +503,7 @@ ExtensionManagerWidget::ExtensionManagerWidget()
m_secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth);
});
connect(m_headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){
- fetchAndInstallPlugin(QUrl::fromUserInput(m_currentItemPlugins.constFirst().second));
+ fetchAndInstallPlugin(QUrl::fromUserInput(m_currentDownloadUrl));
});
connect(m_tags, &TagList::tagSelected, m_extensionBrowser, &ExtensionsBrowser::setFilter);
connect(m_headingWidget, &HeadingWidget::vendorClicked,
@@ -546,7 +527,10 @@ static QString markdownToHtml(const QString &markdown)
blockFormat.setBottomMargin(SpacingTokens::VGapL);
QTextCursor cursor(block);
cursor.mergeBlockFormat(blockFormat);
- const TextFormat headingTf = blockFormat.headingLevel() == 1 ? h5TF : h6TF;
+ const TextFormat headingTf =
+ blockFormat.headingLevel() == 1 ? h5TF
+ : blockFormat.headingLevel() == 2 ? h6TF
+ : h6CapitalTF;
const QFont headingFont = headingTf.font();
for (auto it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment fragment = it.fragment();
@@ -555,9 +539,10 @@ static QString markdownToHtml(const QString &markdown)
cursor.setPosition(fragment.position());
cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
if (blockFormat.hasProperty(QTextFormat::HeadingLevel)) {
+ charFormat.setFontCapitalization(headingFont.capitalization());
charFormat.setFontFamilies(headingFont.families());
- charFormat.setFontWeight(headingFont.weight());
charFormat.setFontPointSize(headingFont.pointSizeF());
+ charFormat.setFontWeight(headingFont.weight());
charFormat.setForeground(headingTf.color());
} else if (charFormat.isAnchor()) {
charFormat.setForeground(creatorColor(Theme::Token_Text_Accent));
@@ -587,96 +572,60 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t)
m_currentItemName = current.data(RoleName).toString();
const bool isPack = current.data(RoleItemType) == ItemTypePack;
m_pluginStatus->setPluginId(isPack ? QString() : current.data(RoleId).toString());
- m_currentItemPlugins = current.data(RolePlugins).value();
-
- auto toContentParagraph = [](const QString &text) {
- const QString pHtml = QString::fromLatin1("%2
")
- .arg(contentTF.lineHeight()).arg(text);
- return pHtml;
- };
+ m_currentDownloadUrl = current.data(RoleDownloadUrl).toString();
{
- const TextData textData = current.data(RoleDescriptionText).value();
- const bool hasDescription = !textData.isEmpty();
- if (hasDescription) {
- QString descriptionMarkdown;
- for (const TextData::Type &text : textData) {
- if (!text.first.isEmpty()) {
- const QLatin1String headingMark(descriptionMarkdown.isEmpty() ? "#" : "\n\n##");
- descriptionMarkdown.append(headingMark + " " + text.first + "\n");
- }
- descriptionMarkdown.append(text.second.join("\n"));
- }
- m_description->setText(markdownToHtml(descriptionMarkdown));
- }
- m_description->setVisible(hasDescription);
-
- const LinksData linksData = current.data(RoleDescriptionLinks).value();
- const bool hasLinks = !linksData.isEmpty();
- if (hasLinks) {
- QString linksHtml;
- const QStringList links = transform(linksData, [](const LinksData::Type &link) {
- const QString anchor = link.first.isEmpty() ? link.second : link.first;
- return QString::fromLatin1(R"(%3 >)")
- .arg(link.second)
- .arg(creatorColor(Theme::Token_Text_Accent).name())
- .arg(anchor);
- });
- linksHtml = links.join("
");
- m_links->setText(toContentParagraph(linksHtml));
- }
- m_linksTitle->setVisible(hasLinks);
- m_links->setVisible(hasLinks);
-
- m_imgTaskTreeRunner.reset();
- m_imageMovie.stop();
- m_imageDataBuffer.close();
- m_image->clear();
- const ImagesData imagesData = current.data(RoleDescriptionImages).value();
- const bool hasImages = !imagesData.isEmpty();
- if (hasImages) {
- const ImagesData::Type &image = imagesData.constFirst(); // Only show one image
- m_imageTitle->setText(image.first);
- fetchAndDisplayImage(image.second);
- }
- m_imageTitle->setVisible(hasImages);
- m_image->setVisible(hasImages);
+ const QStringList description = {
+ "# " + m_currentItemName,
+ current.data(RoleDescriptionShort).toString(),
+ "",
+ current.data(RoleDescriptionLong).toString()
+ };
+ const QString descriptionMarkdown = description.join("\n");
+ m_description->setText(markdownToHtml(descriptionMarkdown));
}
{
+ auto idToDisplayName = [this](const QString &id) {
+ const QModelIndex dependencyIndex = m_extensionModel->indexOfId(id);
+ return dependencyIndex.data(RoleName).toString();
+ };
+
+ auto toContentParagraph = [](const QStringList &text) {
+ const QString lines = text.join("
");
+ const QString pHtml = QString::fromLatin1("%2
")
+ .arg(contentTF.lineHeight()).arg(lines);
+ return pHtml;
+ };
+
const QStringList tags = current.data(RoleTags).toStringList();
m_tags->setTags(tags);
const bool hasTags = !tags.isEmpty();
m_tagsTitle->setVisible(hasTags);
m_tags->setVisible(hasTags);
- const QString compatVersion = current.data(RoleCompatVersion).toString();
- const bool hasCompatVersion = !compatVersion.isEmpty();
- if (hasCompatVersion)
- m_compatVersion->setText(compatVersion);
- m_compatVersionTitle->setVisible(hasCompatVersion);
- m_compatVersion->setVisible(hasCompatVersion);
-
const QStringList platforms = current.data(RolePlatforms).toStringList();
const bool hasPlatforms = !platforms.isEmpty();
if (hasPlatforms)
- m_platforms->setText(toContentParagraph(platforms.join("
")));
+ m_platforms->setText(toContentParagraph(platforms));
m_platformsTitle->setVisible(hasPlatforms);
m_platforms->setVisible(hasPlatforms);
const QStringList dependencies = current.data(RoleDependencies).toStringList();
const bool hasDependencies = !dependencies.isEmpty();
- if (hasDependencies)
- m_dependencies->setText(toContentParagraph(dependencies.join("
")));
+ if (hasDependencies) {
+ const QStringList displayNames = transform(dependencies, idToDisplayName);
+ m_dependencies->setText(toContentParagraph(displayNames));
+ }
m_dependenciesTitle->setVisible(hasDependencies);
m_dependencies->setVisible(hasDependencies);
- const PluginsData plugins = current.data(RolePlugins).value();
+ const QStringList plugins = current.data(RolePlugins).toStringList();
const bool hasExtensions = isPack && !plugins.isEmpty();
if (hasExtensions) {
- const QStringList extensions = transform(plugins, &QPair::first);
- m_packExtensions->setText(toContentParagraph(extensions.join("
")));
+ const QStringList displayNames = transform(plugins, idToDisplayName);
+ m_packExtensions->setText(toContentParagraph(displayNames));
}
m_packExtensionsTitle->setVisible(hasExtensions);
m_packExtensions->setVisible(hasExtensions);
@@ -743,60 +692,6 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url)
m_dlTaskTreeRunner.start(group);
}
-void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url)
-{
- using namespace Tasking;
-
- struct StorageStruct
- {
- QByteArray imageData;
- QUrl url;
- };
- Storage storage;
-
- const auto onFetchSetup = [url, storage](NetworkQuery &query) {
- storage->url = url;
- query.setRequest(QNetworkRequest(url));
- query.setNetworkAccessManager(NetworkAccessManager::instance());
- qCDebug(widgetLog).noquote() << "Sending image request:" << url.toDisplayString();
- };
- const auto onFetchDone = [storage](const NetworkQuery &query, DoneWith result) {
- qCDebug(widgetLog) << "Got image QNetworkReply:" << query.reply()->error();
- if (result == DoneWith::Success)
- storage->imageData = query.reply()->readAll();
- };
-
- const auto onShowImage = [storage, this]() {
- if (storage->imageData.isEmpty())
- return;
- m_imageDataBuffer.setData(storage->imageData);
- qCDebug(widgetLog).noquote() << "Image reponse size:"
- << QLocale::system().formattedDataSize(
- m_imageDataBuffer.size());
- if (!m_imageDataBuffer.open(QIODevice::ReadOnly))
- return;
- QImageReader reader(&m_imageDataBuffer);
- const bool animated = reader.supportsAnimation();
- if (animated) {
- m_image->setMovie(&m_imageMovie);
- m_imageMovie.start();
- } else {
- const QPixmap pixmap = QPixmap::fromImage(reader.read());
- m_image->setPixmap(pixmap);
- }
- qCDebug(widgetLog) << "Image dimensions:" << reader.size();
- qCDebug(widgetLog) << "Image is animated:" << animated;
- };
-
- Group group{
- storage,
- NetworkQueryTask{onFetchSetup, onFetchDone},
- onGroupDone(onShowImage),
- };
-
- m_imgTaskTreeRunner.start(group);
-}
-
QWidget *createExtensionManagerWidget()
{
return new ExtensionManagerWidget;
diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp
index 135fa82e6bc..3bcf0b22b2e 100644
--- a/src/plugins/extensionmanager/extensionsbrowser.cpp
+++ b/src/plugins/extensionmanager/extensionsbrowser.cpp
@@ -277,7 +277,7 @@ public:
painter->setFont(countTF.font());
painter->setPen(countTF.color());
- const PluginsData plugins = index.data(RolePlugins).value();
+ const QStringList plugins = index.data(RolePlugins).toStringList();
painter->drawText(smallCircle, countTF.drawTextFlags, QString::number(plugins.count()));
}
{
@@ -487,10 +487,12 @@ public:
SpinnerSolution::Spinner *m_spinner;
};
-ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
+ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent)
: QWidget(parent)
, d(new ExtensionsBrowserPrivate)
{
+ d->model = model;
+
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
static const TextFormat titleTF
@@ -501,8 +503,6 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
d->searchBox = new SearchBox;
d->searchBox->setPlaceholderText(Tr::tr("Search"));
- d->model = new ExtensionsModel(this);
-
d->searchProxyModel = new QSortFilterProxyModel(this);
d->searchProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
d->searchProxyModel->setFilterRole(RoleSearchText);
@@ -622,28 +622,11 @@ void ExtensionsBrowser::showEvent(QShowEvent *event)
QWidget::showEvent(event);
}
-static QString customOsTypeToString(OsType osType)
-{
- switch (osType) {
- case OsTypeWindows:
- return "Windows";
- case OsTypeLinux:
- return "Linux";
- case OsTypeMac:
- return "macOS";
- case OsTypeOtherUnix:
- return "Other Unix";
- case OsTypeOther:
- default:
- return "Other";
- }
-}
-
void ExtensionsBrowser::fetchExtensions()
{
#ifdef WITH_TESTS
// Uncomment for testing with local json data.
- // Available: "augmentedplugindata", "defaultpacks", "varieddata", "thirdpartyplugins"
+ // Available: "defaultpacks", "thirdpartyplugins"
// d->model->setExtensionsJson(testData("defaultpacks")); return;
#endif // WITH_TESTS
@@ -655,14 +638,8 @@ void ExtensionsBrowser::fetchExtensions()
using namespace Tasking;
const auto onQuerySetup = [this](NetworkQuery &query) {
- const QString url = "%1/api/v1/search?request=";
- const QString requestTemplate
- = R"({"qtc_version":"%1","host_os":"%2","host_os_version":"%3","host_architecture":"%4","page_size":200})";
- const QString request = url.arg(settings().externalRepoUrl()) + requestTemplate
- .arg(QCoreApplication::applicationVersion())
- .arg(customOsTypeToString(HostOsInfo::hostOs()))
- .arg(QSysInfo::productVersion())
- .arg(QSysInfo::currentCpuArchitecture());
+ const QString url = "%1/api/v1/search";
+ const QString request = url.arg(settings().externalRepoUrl());
query.setRequest(QNetworkRequest(QUrl::fromUserInput(request)));
query.setNetworkAccessManager(NetworkAccessManager::instance());
qCDebug(browserLog).noquote() << "Sending JSON request:" << request;
diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h
index f132f598810..0b4254e02cd 100644
--- a/src/plugins/extensionmanager/extensionsbrowser.h
+++ b/src/plugins/extensionmanager/extensionsbrowser.h
@@ -13,12 +13,14 @@ class TextFormat;
namespace ExtensionManager::Internal {
+class ExtensionsModel;
+
class ExtensionsBrowser final : public QWidget
{
Q_OBJECT
public:
- ExtensionsBrowser(QWidget *parent = nullptr);
+ ExtensionsBrowser(ExtensionsModel *model, QWidget *parent = nullptr);
~ExtensionsBrowser();
void setFilter(const QString &filter);
diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp
index 0de838c3983..9415ee02978 100644
--- a/src/plugins/extensionmanager/extensionsmodel.cpp
+++ b/src/plugins/extensionmanager/extensionsmodel.cpp
@@ -5,7 +5,8 @@
#include "extensionmanagertr.h"
-#include "utils/algorithm.h"
+#include
+#include
#include
#include
@@ -21,272 +22,197 @@
#include
#include
-#include
-
using namespace ExtensionSystem;
using namespace Core;
using namespace Utils;
namespace ExtensionManager::Internal {
+const char EXTENSION_KEY_ID[] = "id";
+
Q_LOGGING_CATEGORY(modelLog, "qtc.extensionmanager.model", QtWarningMsg)
-struct Dependency
-{
- QString id;
- QString version;
-};
-using Dependencies = QList;
-
-struct Plugin
-{
- QString copyright;
- Dependencies dependencies;
- bool isInternal = false;
- QString id;
- QString name;
- QString packageUrl;
- QString vendor;
- QString version;
-};
-using Plugins = QList;
-
-struct Description {
- ImagesData images;
- LinksData links;
- TextData text;
-};
-
-struct Extension {
- QString compatVersion;
- QString copyright;
- Description description;
- int downloadCount = -1;
- QString id;
- QString license;
- QString name;
- QStringList platforms;
- Plugins plugins;
- qint64 size = 0;
- QStringList tags;
- ItemType type = ItemTypePack;
- QString vendor;
- QString vendorId;
- QString version;
-};
-using Extensions = QList;
-
-static const Dependencies dependenciesFromJson(const QJsonObject &obj)
-{
- const QJsonArray dependenciesArray = obj.value("Dependencies").toArray();
- Dependencies dependencies;
- for (const QJsonValueConstRef &dependencyVal : dependenciesArray) {
- const QJsonObject dependencyObj = dependencyVal.toObject();
- const QJsonObject metaDataObj = dependencyObj.value("meta_data").toObject();
- dependencies.append({
- .id = metaDataObj.value("Id").toString(),
- .version = metaDataObj.value("Version").toString(),
- });
- }
-
- return dependencies;
-}
-
-static Plugin pluginFromJson(const QJsonObject &obj)
-{
- const QJsonObject metaDataObj = obj.value("meta_data").toObject();
-
- return {
- .copyright = metaDataObj.value("Copyright").toString(),
- .dependencies = dependenciesFromJson(metaDataObj),
- .isInternal = obj.value("is_internal").toBool(false),
- .id = metaDataObj.value("Id").toString(),
- .name = metaDataObj.value("Name").toString(),
- .packageUrl = obj.value("url").toString(),
- .vendor = metaDataObj.value("Vendor").toString(),
- .version = metaDataObj.value("Version").toString(),
- };
-}
-
-static Description descriptionFromJson(const QJsonObject &obj)
-{
- TextData descriptionText;
- const QJsonArray paragraphsArray = obj.value("paragraphs").toArray();
- for (const QJsonValueConstRef ¶graphVal : paragraphsArray) {
- const QJsonObject ¶graphObj = paragraphVal.toObject();
- const QJsonArray &textArray = paragraphObj.value("text").toArray();
- QStringList textLines;
- for (const QJsonValueConstRef &textVal : textArray)
- textLines.append(textVal.toString());
- descriptionText.append({
- paragraphObj.value("header").toString(),
- textLines,
- });
- }
-
- LinksData links;
- const QJsonArray linksArray = obj.value("links").toArray();
- for (const QJsonValueConstRef &linkVal : linksArray) {
- const QJsonObject &linkObj = linkVal.toObject();
- links.append({
- linkObj.value("link_text").toString(),
- linkObj.value("url").toString(),
- });
- }
-
- ImagesData images;
- const QJsonArray imagesArray = obj.value("images").toArray();
- for (const QJsonValueConstRef &imageVal : imagesArray) {
- const QJsonObject &imageObj = imageVal.toObject();
- images.append({
- imageObj.value("image_label").toString(),
- imageObj.value("url").toString(),
- });
- }
-
- const Description description = {
- .images = images,
- .links = links,
- .text = descriptionText,
- };
-
- return description;
-}
-
-static Extension extensionFromJson(const QJsonObject &obj)
-{
- Plugins plugins;
- const QJsonArray pluginsArray = obj.value("plugins").toArray();
- for (const QJsonValueConstRef &pluginVal : pluginsArray)
- plugins.append(pluginFromJson(pluginVal.toObject()));
-
- QStringList tags;
- const QJsonArray tagsArray = obj.value("tags").toArray();
- for (const QJsonValueConstRef &tagVal : tagsArray)
- tags.append(tagVal.toString());
-
- QStringList platforms;
- const QJsonArray platformsArray = obj.value("platforms").toArray();
- for (const QJsonValueConstRef &platformsVal : platformsArray)
- platforms.append(platformsVal.toString());
-
- const QJsonObject descriptionObj = obj.value("description").toObject();
- const Description description = descriptionFromJson(descriptionObj);
-
- const Extension extension = {
- .compatVersion = obj.value("compatibility").toString(),
- .copyright = obj.value("copyright").toString(),
- .description = description,
- .downloadCount = obj.value("download_count").toInt(-1),
- .id = obj.value("id").toString(),
- .license = obj.value("license").toString(),
- .name = obj.value("name").toString(),
- .platforms = platforms,
- .plugins = plugins,
- .size = obj.value("total_size").toInteger(),
- .tags = tags,
- .type = obj.value("is_pack").toBool(true) ? ItemTypePack : ItemTypeExtension,
- .vendor = obj.value("vendor").toString(),
- .vendorId = obj.value("vendor_id").toString(),
- .version = obj.value("version").toString(),
- };
-
- return extension;
-}
-
-static Extensions parseExtensionsRepoReply(const QByteArray &jsonData)
-{
- // https://qc-extensions.qt.io/api-docs
- Extensions parsedExtensions;
- const QJsonObject jsonObj = QJsonDocument::fromJson(jsonData).object();
- const QJsonArray items = jsonObj.value("items").toArray();
- for (const QJsonValueConstRef &itemVal : items) {
- const QJsonObject itemObj = itemVal.toObject();
- const Extension extension = extensionFromJson(itemObj);
- parsedExtensions.append(extension);
- }
- return parsedExtensions;
-}
-
-static Extension extensionFromPluginSpec(const PluginSpec *pluginSpec)
-{
- const Dependencies dependencies
- = transform(pluginSpec->dependencies(), [](const PluginDependency &pd) -> Dependency {
- return {
- .id = pd.id,
- .version = pd.version,
- };
- });
- const Plugin plugin = {
- .copyright = pluginSpec->copyright(),
- .dependencies = dependencies,
- .id = pluginSpec->id(),
- .name = pluginSpec->name(),
- .packageUrl = {},
- .vendor = pluginSpec->vendor(),
- .version = pluginSpec->version(),
- };
-
- const QStringList lines = pluginSpec->description().split('\n')
- + pluginSpec->longDescription().split('\n');
- const TextData text = {{pluginSpec->name(), lines}};
- LinksData links;
- if (const QString url = pluginSpec->url(); !url.isEmpty())
- links.append({{}, url});
- if (const QString docUrl = pluginSpec->documentationUrl(); !docUrl.isEmpty())
- links.append({{Tr::tr("Documentation")}, docUrl});
- const Description description = {
- .images = {},
- .links = links,
- .text = text,
- };
-
- const QString platformsPattern = pluginSpec->platformSpecification().pattern();
- const QStringList platforms = platformsPattern.isEmpty()
- ? QStringList({"macOS", "Windows", "Linux"})
- : QStringList(platformsPattern);
-
- const Extension extension = {
- .compatVersion = pluginSpec->compatVersion(),
- .copyright = pluginSpec->copyright(),
- .description = description,
- .id = pluginSpec->id(),
- .license = pluginSpec->license(),
- .name = pluginSpec->name(),
- .platforms = platforms,
- .plugins = {plugin},
- .tags = {},
- .type = ItemTypeExtension,
- .vendor = pluginSpec->vendor(),
- .vendorId = pluginSpec->vendorId(),
- .version = pluginSpec->version(),
- };
- return extension;
-}
-
class ExtensionsModelPrivate
{
public:
- void setExtensions(const Extensions &extensions);
- void addUnlistedLocalExtensions();
+ void addUnlistedLocalPlugins();
- Extensions extensions;
+ static QVariant dataFromRemotePack(const QJsonObject &json, int role);
+ static QVariant dataFromRemotePlugin(const QJsonObject &json, int role);
+ QVariant dataFromRemoteExtension(int index, int role) const;
+ QVariant dataFromLocalPlugin(int index, int role) const;
+
+ QJsonArray responseItems;
+ PluginSpecs localPlugins;
};
-void ExtensionsModelPrivate::setExtensions(const Extensions &extensions)
+void ExtensionsModelPrivate::addUnlistedLocalPlugins()
{
- this->extensions = extensions;
- qCDebug(modelLog) << "Number of extensions from JSON:" << this->extensions.count();
- addUnlistedLocalExtensions();
- qCDebug(modelLog) << "Number of extensions with added local ones:" << this->extensions.count();
+ QStringList responseExtensions;
+ for (const QJsonValueConstRef &responseItem : responseItems)
+ responseExtensions << responseItem.toObject().value("id").toString();
+
+ localPlugins.clear();
+ for (PluginSpec *plugin : PluginManager::plugins())
+ if (!responseExtensions.contains(plugin->id()))
+ localPlugins.append(plugin);
+
+ qCDebug(modelLog) << "Number of extensions from JSON:" << responseExtensions.count();
+ qCDebug(modelLog) << "Number of added local plugins:" << localPlugins.count();
}
-void ExtensionsModelPrivate::addUnlistedLocalExtensions()
+QString joinedStringList(const QJsonValue &json)
{
- const QStringList listedModelExtensions = transform(extensions, &Extension::name);
- for (const PluginSpec *plugin : PluginManager::plugins())
- if (!listedModelExtensions.contains(plugin->name()))
- extensions.append(extensionFromPluginSpec(plugin));
+ if (json.isArray()) {
+ const QStringList lines = json.toVariant().toStringList();
+ return lines.join("\n");
+ }
+ return json.toString();
+}
+
+QString descriptionWithLinks(const QString &description, const QString &url,
+ const QString &documentationUrl)
+{
+ QStringList fragments;
+ const QString mdLink("[%1](%2)");
+ if (!url.isEmpty())
+ fragments.append(mdLink.arg(url).arg(url));
+ if (!documentationUrl.isEmpty())
+ fragments.append(mdLink.arg(Tr::tr("Documentation")).arg(documentationUrl));
+ if (!fragments.isEmpty())
+ fragments.prepend("### " + Tr::tr("More Information"));
+ fragments.prepend(description);
+ return fragments.join("\n\n");
+}
+
+QVariant ExtensionsModelPrivate::dataFromRemotePack(const QJsonObject &json, int role)
+{
+ switch (role) {
+ case RoleDescriptionLong:
+ return joinedStringList(json.value("long_description"));
+ case RoleDescriptionShort:
+ return joinedStringList(json.value("description"));
+ case RoleItemType:
+ return ItemTypePack;
+ case RolePlugins:
+ return json.value("plugins").toVariant().toStringList();
+ default:
+ break;
+ }
+
+ return {};
+}
+
+QVariant ExtensionsModelPrivate::dataFromRemotePlugin(const QJsonObject &json, int role)
+{
+ const QJsonObject metaData = json.value("metadata").toObject();
+
+ switch (role) {
+ case RoleCopyright:
+ return metaData.value("Copyright");
+ case RoleDownloadUrl: {
+ const QJsonArray sources = json.value("sources").toArray();
+ const QString thisPlatform = customOsTypeToString(HostOsInfo::hostOs());
+ const QString thisArch = QSysInfo::currentCpuArchitecture();
+ for (const QJsonValue source : sources) {
+ const QJsonObject sourceObject = source.toObject();
+ const QJsonObject platform = sourceObject.value("platform").toObject();
+ if (platform.isEmpty() // Might be a Lua plugin
+ || (platform.value("name").toString() == thisPlatform
+ && platform.value("architecture") == thisArch))
+ return sourceObject.value("url").toString();
+ }
+ break;
+ }
+ case RoleItemType:
+ return ItemTypeExtension;
+ case RoleDescriptionLong: {
+ const QString description = joinedStringList(metaData.value("LongDescription"));
+ const QString url = metaData.value("Url").toString();
+ const QString documentationUrl = metaData.value("DocumentationUrl").toString();
+ return descriptionWithLinks(description, url, documentationUrl);
+ }
+ case RoleDescriptionShort:
+ return joinedStringList(metaData.value("Description"));
+ default:
+ break;
+ }
+
+ return {};
+}
+
+QVariant ExtensionsModelPrivate::dataFromRemoteExtension(int index, int role) const
+{
+ const QJsonObject json = responseItems.at(index).toObject();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case RoleName:
+ return json.value("display_name");
+ case RoleDownloadCount:
+ return json.value("downloads");
+ case RoleId:
+ return json.value(EXTENSION_KEY_ID);
+ case RoleTags:
+ return json.value("tags").toVariant().toStringList();
+ case RoleVendor:
+ return json.value("display_vendor");
+ default:
+ break;
+ }
+
+ const QJsonObject pluginObject = json.value("plugin").toObject();
+ if (!pluginObject.isEmpty())
+ return dataFromRemotePlugin(pluginObject, role);
+
+ const QJsonObject packObject = json.value("pack").toObject();
+ if (!packObject.isEmpty())
+ return dataFromRemotePack(packObject, role);
+
+ return {};
+}
+
+QVariant ExtensionsModelPrivate::dataFromLocalPlugin(int index, int role) const
+{
+ const PluginSpec *pluginSpec = localPlugins.at(index);
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case RoleName:
+ return pluginSpec->displayName();
+ case RoleCopyright:
+ return pluginSpec->copyright();
+ case RoleDependencies: {
+ const QStringList dependencies
+ = transform(pluginSpec->dependencies(), &PluginDependency::id);
+ return dependencies;
+ }
+ case RoleDescriptionLong:
+ return descriptionWithLinks(pluginSpec->longDescription(), pluginSpec->url(),
+ pluginSpec->documentationUrl());
+ case RoleDescriptionShort:
+ return pluginSpec->description();
+ case RoleId:
+ return pluginSpec->id();
+ case RoleItemType:
+ return ItemTypeExtension;
+ case RolePlatforms: {
+ const QString platformsPattern = pluginSpec->platformSpecification().pattern();
+ const QStringList platforms = platformsPattern.isEmpty()
+ ? QStringList({customOsTypeToString(OsTypeMac),
+ customOsTypeToString(OsTypeWindows),
+ customOsTypeToString(OsTypeLinux)})
+ : QStringList(platformsPattern);
+ return platforms;
+ }
+ case RoleVendor:
+ return pluginSpec->vendor();
+ case RoleVendorId:
+ return pluginSpec->vendorId();
+ default:
+ break;
+ }
+ return {};
}
ExtensionsModel::ExtensionsModel(QObject *parent)
@@ -302,77 +228,7 @@ ExtensionsModel::~ExtensionsModel()
int ExtensionsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
{
- return d->extensions.count();
-}
-
-static QStringList dependenciesFromExtension(const Extension &extension)
-{
- QStringList dependencies;
- for (const Plugin &plugin : extension.plugins) {
- for (const Dependency &dependency : plugin.dependencies) {
- const QString withVersion
- = QString::fromLatin1("%1 (%2)").arg(dependency.id).arg(dependency.version);
- dependencies.append(withVersion);
- }
- }
- dependencies.sort();
- dependencies.removeDuplicates();
- return dependencies;
-}
-
-static QVariant dataFromExtension(const Extension &extension, int role)
-{
- switch (role) {
- case Qt::DisplayRole:
- case RoleName:
- return Utils::findOr(
- QStringList{extension.name, extension.id},
- "No name found",
- std::not_fn(&QString::isEmpty));
- case RoleCompatVersion:
- return extension.compatVersion;
- case RoleCopyright:
- return !extension.copyright.isEmpty() ? extension.copyright : QVariant();
- case RoleDependencies:
- return dependenciesFromExtension(extension);
- case RoleDescriptionImages:
- return QVariant::fromValue(extension.description.images);
- case RoleDescriptionLinks:
- return QVariant::fromValue(extension.description.links);
- case RoleDescriptionText:
- return QVariant::fromValue(extension.description.text);
- case RoleDownloadCount:
- return extension.downloadCount;
- case RoleId:
- return extension.id;
- case RoleItemType:
- return extension.type;
- case RoleLicense:
- return extension.license;
- case RoleLocation:
- break;
- case RolePlatforms:
- return extension.platforms;
- case RolePlugins: {
- PluginsData plugins;
- for (const Plugin &plugin : extension.plugins)
- plugins.append(qMakePair(plugin.id, plugin.packageUrl));
- return QVariant::fromValue(plugins);
- }
- case RoleSize:
- return extension.size;
- case RoleTags:
- return extension.tags;
- case RoleVendor:
- return !extension.vendor.isEmpty() ? extension.vendor : QVariant();
- case RoleVersion:
- return !extension.version.isEmpty() ? extension.version : QVariant();
- case RoleVendorId:
- return extension.vendorId;
- default:
- break;
- }
- return {};
+ return d->responseItems.count() + d->localPlugins.count();
}
ExtensionState extensionState(const QModelIndex &index)
@@ -392,10 +248,8 @@ static QString searchText(const QModelIndex &index)
QStringList searchTexts;
searchTexts.append(index.data(RoleName).toString());
searchTexts.append(index.data(RoleTags).toStringList());
- for (const auto &data : index.data(RoleDescriptionText).value()) {
- searchTexts.append(data.first);
- searchTexts.append(data.second);
- }
+ searchTexts.append(index.data(RoleDescriptionShort).toString());
+ searchTexts.append(index.data(RoleDescriptionLong).toString());
searchTexts.append(index.data(RoleVendor).toString());
return searchTexts.join(" ");
}
@@ -407,28 +261,56 @@ QVariant ExtensionsModel::data(const QModelIndex &index, int role) const
if (role == RoleSearchText)
return searchText(index);
- const Extension &extension = d->extensions.at(index.row());
- const QVariant extensionData = dataFromExtension(extension, role);
- // If data is unavailable, retrieve it from the first contained plugin
- if (extensionData.isNull() && !extension.plugins.isEmpty()) {
- const QString firstPluginId = extension.plugins.constFirst().id;
- const Extension firstPluginExtension
- = findOrDefault(d->extensions, Utils::equal(&Extension::id, firstPluginId));
- if (firstPluginExtension.name.isEmpty())
- return {};
- return dataFromExtension(firstPluginExtension, role);
+ const bool isRemoteExtension = index.row() < d->responseItems.count();
+ const int itemIndex = index.row() - (isRemoteExtension ? 0 : d->responseItems.count());
+
+ return isRemoteExtension ? d->dataFromRemoteExtension(itemIndex, role)
+ : d->dataFromLocalPlugin(itemIndex, role);
+}
+
+QModelIndex ExtensionsModel::indexOfId(const QString &extensionId) const
+{
+ const int localIndex = indexOf(d->localPlugins, equal(&PluginSpec::id, extensionId));
+ if (localIndex >= 0)
+ return index(d->responseItems.count() + localIndex);
+
+ for (int remoteIndex = 0; const QJsonValueConstRef vlaue : d->responseItems) {
+ if (vlaue.toObject().value(EXTENSION_KEY_ID) == extensionId)
+ return index(remoteIndex);
+ ++remoteIndex;
}
- return extensionData;
+
+ return {};
}
void ExtensionsModel::setExtensionsJson(const QByteArray &json)
{
- const Extensions extensions = parseExtensionsRepoReply(json);
beginResetModel();
- d->setExtensions(extensions);
+ QJsonParseError error;
+ const QJsonObject jsonObj = QJsonDocument::fromJson(json, &error).object();
+ qCDebug(modelLog) << "QJsonParseError:" << error.errorString();
+ d->responseItems = jsonObj.value("items").toArray();
+ d->addUnlistedLocalPlugins();
endResetModel();
}
+QString customOsTypeToString(OsType osType)
+{
+ switch (osType) {
+ case OsTypeWindows:
+ return "Windows";
+ case OsTypeLinux:
+ return "Linux";
+ case OsTypeMac:
+ return "macOS";
+ case OsTypeOtherUnix:
+ return "Other Unix";
+ case OsTypeOther:
+ default:
+ return "Other";
+ }
+}
+
PluginSpec *pluginSpecForId(const QString &pluginId)
{
return findOrDefault(PluginManager::plugins(), equal(&PluginSpec::id, pluginId));
diff --git a/src/plugins/extensionmanager/extensionsmodel.h b/src/plugins/extensionmanager/extensionsmodel.h
index e837c2ae452..e8f47828ad0 100644
--- a/src/plugins/extensionmanager/extensionsmodel.h
+++ b/src/plugins/extensionmanager/extensionsmodel.h
@@ -3,6 +3,8 @@
#pragma once
+#include
+
#include
namespace ExtensionSystem {
@@ -11,13 +13,6 @@ class PluginSpec;
namespace ExtensionManager::Internal {
-using QPairList = QList >;
-
-using ImagesData = QPairList; // { , ... }
-using LinksData = QPairList; // { , ... }
-using PluginsData = QPairList; // { , ... }
-using TextData = QList >; // { , ... }
-
enum ItemType {
ItemTypePack,
ItemTypeExtension,
@@ -32,22 +27,19 @@ enum ExtensionState {
enum Role {
RoleName = Qt::UserRole,
- RoleCompatVersion,
RoleCopyright,
RoleDependencies,
- RoleDescriptionImages,
- RoleDescriptionLinks,
- RoleDescriptionText,
+ RoleDescriptionLong,
+ RoleDescriptionShort,
RoleDownloadCount,
+ RoleDownloadUrl,
RoleExtensionState,
RoleId,
RoleItemType,
RoleLicense,
- RoleLocation,
RolePlatforms,
RolePlugins,
RoleSearchText,
- RoleSize,
RoleTags,
RoleVendor,
RoleVendorId,
@@ -63,12 +55,14 @@ public:
int rowCount(const QModelIndex &parent = {}) const;
QVariant data(const QModelIndex &index, int role) const;
+ QModelIndex indexOfId(const QString &extensionId) const;
void setExtensionsJson(const QByteArray &json);
private:
class ExtensionsModelPrivate *d = nullptr;
};
+QString customOsTypeToString(Utils::OsType osType);
ExtensionSystem::PluginSpec *pluginSpecForId(const QString &pluginId);
#ifdef WITH_TESTS
@@ -76,6 +70,3 @@ QObject *createExtensionsModelTest();
#endif
} // ExtensionManager::Internal
-
-Q_DECLARE_METATYPE(ExtensionManager::Internal::QPairList)
-Q_DECLARE_METATYPE(ExtensionManager::Internal::TextData)
diff --git a/src/plugins/extensionmanager/testdata/augmentedplugindata.json b/src/plugins/extensionmanager/testdata/augmentedplugindata.json
deleted file mode 100644
index 32efe15b708..00000000000
--- a/src/plugins/extensionmanager/testdata/augmentedplugindata.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "items": [
- {
- "name": "ScreenRecorder",
- "description": {
- "paragraphs": [
- {
- "header": "Screen Recorder plugin",
- "text": [
- "With FFmpeg, you can record your screens and save the recordings as animated images or videos.",
- "To record screens:",
- "",
- "- Select Tools > Screen Recording.",
- "- Select to select the screen to record from and to set the recorded screen area.",
- "- Select to start recording.",
- "- Select when you are done recording.",
- "- Select Crop and Trim to edit the recording.",
- "- Select Export to save the recording as an animated image or a video."
- ]
- },
- {
- "header": "Set the screen and area to record",
- "text": [
- "Set the screen and the area to record in the Screen Recording Options dialog.",
- "To select a screen and area:",
- "",
- "- In Display, select the display to record.",
- "- In Recorded screen area, drag the guides to set the x and y coordinates of the starting point for the recording area, as well as the width and height of the area.",
- "- Select OK to return to the Record Screen dialog."
- ]
- }
- ],
- "images": [
- {
- "image_label": "Create animated imges like this",
- "url": "https://bugreports.qt.io/secure/attachment/156058/156058_DragAndCopyOnLinux.gif"
- }
- ],
- "links": [
- {
- "link_text": "Documentation",
- "url": "https://doc.qt.io/qtcreator/creator-how-to-record-screens.html"
- },
- {
- "link_text": "Homepage",
- "url": "https://www.qt.io/"
- }
- ]
- },
- "is_pack": false,
- "plugins": [
- {
- "meta_data": {
- "Name": "ScreenRecorder",
- "Dependencies": [
- {
- "meta_data": {
- "Name": "Core",
- "Version": "13.0.2"
- }
- }
- ],
- "Version": "13.0.2"
- }
- }
- ],
- "tags": [ "Utility", "Docs" ],
- "vendor": "The Qt Company Ltd"
- }
- ]
-}
diff --git a/src/plugins/extensionmanager/testdata/defaultpacks.json b/src/plugins/extensionmanager/testdata/defaultpacks.json
index d26b0a42c60..95b6d5920da 100644
--- a/src/plugins/extensionmanager/testdata/defaultpacks.json
+++ b/src/plugins/extensionmanager/testdata/defaultpacks.json
@@ -1,126 +1,114 @@
{
"items": [
+
{
- "name": "Essentials",
+ "id": "essentials",
+ "display_name": "Essentials",
"tags": [ "Essentials" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": true,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Basic services, such as editing and debugging code, viewing images, and adding resources to applications."
- ],
- "header": "Get started"
- }
+ "license": "open-source",
+ "vendor_id": "theqtcompany",
+ "display_vendor": "The Qt Company",
+ "version": "14.0.2",
+ "pack": {
+ "description": "Get started",
+ "long_description": [
+ "Basic services, such as editing and debugging code, viewing images, and adding resources to applications.",
+ "",
+ "Online documentation: https://doc.qt.io/qtcreator/creator-coding-navigating.html"
],
- "links": [
- {
- "url": "https://doc.qt.io/qtcreator/creator-coding-navigating.html",
- "link_text": "Online documentation"
- }
+ "plugins": [
+ "bineditor",
+ "debugger",
+ "diffeditor",
+ "imageviewer",
+ "macros",
+ "languageclient",
+ "resourceeditor"
]
- },
- "plugins": [
- { "meta_data": { "Name": "BinEditor" } },
- { "meta_data": { "Name": "Debugger" } },
- { "meta_data": { "Name": "DiffEditor" } },
- { "meta_data": { "Name": "ImageViewer" } },
- { "meta_data": { "Name": "Macros" } },
- { "meta_data": { "Name": "LanguageClient" } },
- { "meta_data": { "Name": "ResourceEditor" } }
- ]
+ }
},
{
- "name": "C++ Support",
+ "id": "cppsupport",
+ "display_name": "C++ Support",
"tags": [ "Programming Language", "C++" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": true,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Tools for developing Qt C++ applications."
- ],
- "header": "Get started"
- }
+ "license": "open-source",
+ "vendor_id": "theqtcompany",
+ "display_vendor": "The Qt Company",
+ "version": "14.0.2",
+ "pack": {
+ "description": "Get started",
+ "long_description": [
+ "Tools for developing Qt C++ applications."
+ ],
+ "plugins": [
+ "clangcodemodel",
+ "clangformat",
+ "classview",
+ "cppeditor"
]
- },
- "plugins": [
- { "meta_data": { "Name": "ClangCodeModel" } },
- { "meta_data": { "Name": "ClangFormat" } },
- { "meta_data": { "Name": "ClassView" } },
- { "meta_data": { "Name": "CppEditor" } }
- ]
+ }
},
{
- "name": "QML Support",
+ "id": "qmlsupport",
+ "display_name": "QML Support",
"tags": [ "Programming Language", "QML" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": true,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Tools for developing Qt Quick applications."
- ],
- "header": "Get started"
- }
+ "license": "open-source",
+ "vendor_id": "theqtcompany",
+ "display_vendor": "The Qt Company",
+ "version": "14.0.2",
+ "pack": {
+ "description": "Get started",
+ "long_description": [
+ "Tools for developing Qt Quick applications."
+ ],
+ "plugins": [
+ "qmljseditor",
+ "qmljstools",
+ "qmlpreview",
+ "qmlprofiler"
]
- },
- "plugins": [
- { "meta_data": { "Name": "QmlJSEditor" } },
- { "meta_data": { "Name": "QmlJSTools" } },
- { "meta_data": { "Name": "QmlPreview" } },
- { "meta_data": { "Name": "QmlProfiler" } }
- ]
+ }
},
{
- "name": "Visual QML Editor",
+ "id": "visualqmleditor",
+ "display_name": "Visual QML Editor",
"tags": [ "Visual UI editor", "qml", "Quick" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": true,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Tools for creating Qt Quick UIs."
- ],
- "header": "Get started"
- }
+ "license": "open-source",
+ "vendor_id": "theqtcompany",
+ "display_vendor": "The Qt Company",
+ "version": "14.0.2",
+ "pack": {
+ "description": "Get started",
+ "long_description": [
+ "Tools for creating Qt Quick UIs."
+ ],
+ "plugins": [
+ "qmldesigner"
]
- },
- "plugins": [
- { "meta_data": { "Name": "QmlDesigner" } }
- ]
+ }
},
{
- "name": "Visual Widget Editor",
+ "id": "visualwidgeteditor",
+ "display_name": "Visual Widget Editor",
"tags": [ "Visual UI editor", "C++", "Widgets" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": true,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Visual tool for creating Qt widget-based UIs."
- ],
- "header": "Get started"
- }
+ "license": "open-source",
+ "vendor_id": "theqtcompany",
+ "display_vendor": "The Qt Company",
+ "version": "14.0.2",
+ "pack": {
+ "description": "Get started",
+ "long_description": [
+ "Visual tool for creating Qt widget-based UIs."
+ ],
+ "plugins": [
+ "designer"
]
- },
- "plugins": [
- { "meta_data": { "Name": "Designer" } }
- ]
+ }
}
+
]
}
diff --git a/src/plugins/extensionmanager/testdata/thirdpartyplugins.json b/src/plugins/extensionmanager/testdata/thirdpartyplugins.json
index 910854a68f8..2f79b994920 100644
--- a/src/plugins/extensionmanager/testdata/thirdpartyplugins.json
+++ b/src/plugins/extensionmanager/testdata/thirdpartyplugins.json
@@ -1,38 +1,49 @@
{
"items": [
+
{
- "name": "SpellChecker",
+ "id": "spellchecker",
+ "display_name": "SpellChecker",
"tags": [ "Editor" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": false,
- "description": {
- "paragraphs": [
+ "license": "open-source",
+ "vendor_id": "carelcombrink",
+ "display_vendor": "Carel Combrink",
+ "downloads": 2333,
+ "plugin": {
+ "metadata": {
+ "Copyright": "(C) 2015 - 2024 Carel Combrink",
+ "Description": "Foo",
+ "LongDescription": [
+ "Spellcheck comments in source files."
+ ],
+ "Url" : "https://github.com/CJCombrink/SpellChecker-Plugin",
+ "DocumentationUrl" : "https://github.com/CJCombrink/SpellChecker-Plugin?tab=readme-ov-file#spellchecker-plugin"
+ },
+ "sources": [
{
- "text": [
- "Spellcheck comments in source files."
- ],
- "header": "Get started"
- }
- ],
- "links": [
+ "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.7.0/SpellChecker-Plugin_QtC14.0.0_linux_x64.tar.gz",
+ "platform": {
+ "name": "Linux",
+ "architecture": "x86_64"
+ }
+ },
{
- "url": "https://github.com/CJCombrink/SpellChecker-Plugin",
- "link_text": "GitHub page"
+ "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.7.0/SpellChecker-Plugin_QtC14.0.0_macos_x64.tar.gz",
+ "platform": {
+ "name": "macOS",
+ "architecture": "x86_64"
+ }
+ },
+ {
+ "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.7.0/SpellChecker-Plugin_QtC14.0.0_win64_x64.zip",
+ "platform": {
+ "name": "Windows",
+ "architecture": "x86_64"
+ }
}
]
- },
- "plugins": [
- {
- "meta_data": {
- "Name": "SpellChecker",
- "Copyright": "(C) 2015 - 2024 Carel Combrink"
- },
- "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.6.0/SpellChecker-Plugin_QtC13.0.0_macos_x64.tar.gz"
- }
- ],
- "vendor": "Carel Combrink",
- "copyright": "(C) 2015 - 2024 Carel Combrink"
+ }
}
+
]
}
diff --git a/src/plugins/extensionmanager/testdata/varieddata.json b/src/plugins/extensionmanager/testdata/varieddata.json
deleted file mode 100644
index 245d08ad844..00000000000
--- a/src/plugins/extensionmanager/testdata/varieddata.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "items": [
- {
- "name": "Few tags",
- "tags": [ "Tag one", "Tag two"]
- },
-
- {
- "name": "Many tags",
- "tags": [ "Tag_01", "Tag_02", "Tag_03", "Tag_04", "Tag_05", "Tag_06", "Tag_07", "Tag_08", "Tag_09", "Tag_10", "Tag_11", "Tag_12", "Tag_13", "Tag_14", "Tag_15", "Tag_16", "Tag_17", "Tag_18", "Tag_19", "Tag_20", "Tag_21", "Tag_22", "Tag_23", "Tag_24", "Tag_25", "Tag_26", "Tag_27", "Tag_28", "Tag_29", "Tag_30", "And_a_very_long_tag_without_spaces", "Ok, a last long tag without spaces, but that sgould be enough"],
- "description": {
- "paragraphs": [
- {
- "text": [
- "... and a few long ones"
- ]
- }
- ]
- }
- },
-
- {
- "name": "One static image",
- "description": {
- "paragraphs": [
- {
- "text": [
- "png"
- ]
- }
- ],
- "images": [
- {
- "image_label": "Screenshot",
- "url": "https://bugreports.qt.io/secure/attachment/147354/VirtualNodesShownAsNotExisting.png"
- }
- ]
- }
- },
-
- {
- "name": "One animated image",
- "description": {
- "paragraphs": [
- {
- "text": [
- "gif (animated)"
- ]
- }
- ],
- "images": [
- {
- "image_label": "Screencast",
- "url": "https://bugreports.qt.io/secure/attachment/156058/156058_DragAndCopyOnLinux.gif"
- }
- ]
- }
- },
-
- {
- "name": "Vendor, no download count",
- "vendor": "Vendor name"
- },
-
- {
- "name": "No vendor, but download count",
- "download_count": 12345
- },
-
- {
- "name": "Vendor and download count",
- "vendor": "Vendor name",
- "download_count": 12345
- }
- ]
-}