ExtensionManager: Hide ExtensionManagerWidget class in .cpp

And de-pimpl. Smaller overall interface and less indirections.

Change-Id: If6a5c0824581a6478ad6e88410d97e23cc517a53
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
hjk
2024-06-26 08:38:51 +02:00
parent a48fcfecd4
commit be84c74cb9
3 changed files with 126 additions and 133 deletions

View File

@@ -50,7 +50,7 @@ public:
using namespace Layouting; using namespace Layouting;
auto widget = Column { auto widget = Column {
new StyledBar, new StyledBar,
new ExtensionManagerWidget, createExtensionManagerWidget(),
noMargin, spacing(0), noMargin, spacing(0),
}.emerge(); }.emerge();

View File

@@ -399,166 +399,166 @@ private:
QSignalMapper *m_signalMapper; QSignalMapper *m_signalMapper;
}; };
class ExtensionManagerWidgetPrivate class ExtensionManagerWidget final : public Core::ResizeSignallingWidget
{ {
public: public:
QString currentItemName; ExtensionManagerWidget();
ExtensionsBrowser *extensionBrowser;
CollapsingWidget *secondaryDescriptionWidget; private:
HeadingWidget *headingWidget; void updateView(const QModelIndex &current);
QWidget *primaryContent; void fetchAndInstallPlugin(const QUrl &url);
QWidget *secondaryContent; void fetchAndDisplayImage(const QUrl &url);
QLabel *description;
QLabel *linksTitle; QString m_currentItemName;
QLabel *links; ExtensionsBrowser *m_extensionBrowser;
QLabel *imageTitle; CollapsingWidget *m_secondaryDescriptionWidget;
QLabel *image; HeadingWidget *m_headingWidget;
QBuffer imageDataBuffer; QWidget *m_primaryContent;
QMovie imageMovie; QWidget *m_secondaryContent;
QLabel *tagsTitle; QLabel *m_description;
TagList *tags; QLabel *m_linksTitle;
QLabel *platformsTitle; QLabel *m_links;
QLabel *platforms; QLabel *m_imageTitle;
QLabel *dependenciesTitle; QLabel *m_image;
QLabel *dependencies; QBuffer m_imageDataBuffer;
QLabel *packExtensionsTitle; QMovie m_imageMovie;
QLabel *packExtensions; QLabel *m_tagsTitle;
PluginStatusWidget *pluginStatus; TagList *m_tags;
PluginsData currentItemPlugins; QLabel *m_platformsTitle;
Tasking::TaskTreeRunner dlTaskTreeRunner; QLabel *m_platforms;
Tasking::TaskTreeRunner imgTaskTreeRunner; QLabel *m_dependenciesTitle;
QLabel *m_dependencies;
QLabel *m_packExtensionsTitle;
QLabel *m_packExtensions;
PluginStatusWidget *m_pluginStatus;
PluginsData m_currentItemPlugins;
Tasking::TaskTreeRunner m_dlTaskTreeRunner;
Tasking::TaskTreeRunner m_imgTaskTreeRunner;
}; };
ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent) ExtensionManagerWidget::ExtensionManagerWidget()
: ResizeSignallingWidget(parent)
, d(new ExtensionManagerWidgetPrivate)
{ {
d->extensionBrowser = new ExtensionsBrowser; m_extensionBrowser = new ExtensionsBrowser;
auto descriptionColumns = new QWidget; auto descriptionColumns = new QWidget;
d->secondaryDescriptionWidget = new CollapsingWidget; m_secondaryDescriptionWidget = new CollapsingWidget;
d->headingWidget = new HeadingWidget; m_headingWidget = new HeadingWidget;
d->description = tfLabel(contentTF, false); m_description = tfLabel(contentTF, false);
d->description->setWordWrap(true); m_description->setWordWrap(true);
d->linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information"));
d->links = tfLabel(contentTF, false); m_links = tfLabel(contentTF, false);
d->links->setOpenExternalLinks(true); m_links->setOpenExternalLinks(true);
d->imageTitle = sectionTitle(h6CapitalTF, {}); m_imageTitle = sectionTitle(h6CapitalTF, {});
d->image = new QLabel; m_image = new QLabel;
d->imageMovie.setDevice(&d->imageDataBuffer); m_imageMovie.setDevice(&m_imageDataBuffer);
using namespace Layouting; using namespace Layouting;
auto primary = new QWidget; auto primary = new QWidget;
const auto spL = spacing(SpacingTokens::VPaddingL); const auto spL = spacing(SpacingTokens::VPaddingL);
Column { Column {
d->description, m_description,
Column { d->linksTitle, d->links, spL }, Column { m_linksTitle, m_links, spL },
Column { d->imageTitle, d->image, spL }, Column { m_imageTitle, m_image, spL },
st, st,
noMargin, spacing(SpacingTokens::ExVPaddingGapXl), noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
}.attachTo(primary); }.attachTo(primary);
d->primaryContent = toScrollableColumn(primary); m_primaryContent = toScrollableColumn(primary);
d->tagsTitle = sectionTitle(h6TF, Tr::tr("Tags")); m_tagsTitle = sectionTitle(h6TF, Tr::tr("Tags"));
d->tags = new TagList; m_tags = new TagList;
d->platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms")); m_platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms"));
d->platforms = tfLabel(contentTF, false); m_platforms = tfLabel(contentTF, false);
d->dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies")); m_dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies"));
d->dependencies = tfLabel(contentTF, false); m_dependencies = tfLabel(contentTF, false);
d->packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack")); m_packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack"));
d->packExtensions = tfLabel(contentTF, false); m_packExtensions = tfLabel(contentTF, false);
d->pluginStatus = new PluginStatusWidget; m_pluginStatus = new PluginStatusWidget;
auto secondary = new QWidget; auto secondary = new QWidget;
const auto spXxs = spacing(SpacingTokens::VPaddingXxs); const auto spXxs = spacing(SpacingTokens::VPaddingXxs);
Column { Column {
sectionTitle(h6CapitalTF, Tr::tr("Extension details")), sectionTitle(h6CapitalTF, Tr::tr("Extension details")),
Column { Column {
Column { d->tagsTitle, d->tags, spXxs }, Column { m_tagsTitle, m_tags, spXxs },
Column { d->platformsTitle, d->platforms, spXxs }, Column { m_platformsTitle, m_platforms, spXxs },
Column { d->dependenciesTitle, d->dependencies, spXxs }, Column { m_dependenciesTitle, m_dependencies, spXxs },
Column { d->packExtensionsTitle, d->packExtensions, spXxs }, Column { m_packExtensionsTitle, m_packExtensions, spXxs },
spacing(SpacingTokens::VPaddingL), spacing(SpacingTokens::VPaddingL),
}, },
st, st,
noMargin, spacing(SpacingTokens::ExVPaddingGapXl), noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
}.attachTo(secondary); }.attachTo(secondary);
d->secondaryContent = toScrollableColumn(secondary); m_secondaryContent = toScrollableColumn(secondary);
Row { Row {
WelcomePageHelpers::createRule(Qt::Vertical), WelcomePageHelpers::createRule(Qt::Vertical),
Column { Column {
d->secondaryContent, m_secondaryContent,
d->pluginStatus, m_pluginStatus,
}, },
noMargin, spacing(0), noMargin, spacing(0),
}.attachTo(d->secondaryDescriptionWidget); }.attachTo(m_secondaryDescriptionWidget);
Row { Row {
WelcomePageHelpers::createRule(Qt::Vertical), WelcomePageHelpers::createRule(Qt::Vertical),
Row { Row {
Column { Column {
Column { Column {
d->headingWidget, m_headingWidget,
customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl, customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl,
SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl), SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl),
}, },
d->primaryContent, m_primaryContent,
}, },
}, },
d->secondaryDescriptionWidget, m_secondaryDescriptionWidget,
noMargin, spacing(0), noMargin, spacing(0),
}.attachTo(descriptionColumns); }.attachTo(descriptionColumns);
Row { Row {
Space(SpacingTokens::ExVPaddingGapXl), Space(SpacingTokens::ExVPaddingGapXl),
d->extensionBrowser, m_extensionBrowser,
descriptionColumns, descriptionColumns,
noMargin, spacing(0), noMargin, spacing(0),
}.attachTo(this); }.attachTo(this);
WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default); WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default);
connect(d->extensionBrowser, &ExtensionsBrowser::itemSelected, connect(m_extensionBrowser, &ExtensionsBrowser::itemSelected,
this, &ExtensionManagerWidget::updateView); this, &ExtensionManagerWidget::updateView);
connect(this, &ResizeSignallingWidget::resized, this, [this](const QSize &size) { connect(this, &ResizeSignallingWidget::resized, this, [this](const QSize &size) {
const int intendedBrowserColumnWidth = size.width() - 580; const int intendedBrowserColumnWidth = size.width() - 580;
d->extensionBrowser->adjustToWidth(intendedBrowserColumnWidth); m_extensionBrowser->adjustToWidth(intendedBrowserColumnWidth);
const bool secondaryDescriptionVisible = size.width() > 970; const bool secondaryDescriptionVisible = size.width() > 970;
const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0; const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0;
d->secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth); m_secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth);
}); });
connect(d->headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){ connect(m_headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){
fetchAndInstallPlugin(QUrl::fromUserInput(d->currentItemPlugins.constFirst().second)); fetchAndInstallPlugin(QUrl::fromUserInput(m_currentItemPlugins.constFirst().second));
}); });
connect(d->tags, &TagList::tagSelected, d->extensionBrowser, &ExtensionsBrowser::setFilter); connect(m_tags, &TagList::tagSelected, m_extensionBrowser, &ExtensionsBrowser::setFilter);
connect(d->headingWidget, &HeadingWidget::vendorClicked, connect(m_headingWidget, &HeadingWidget::vendorClicked,
d->extensionBrowser, &ExtensionsBrowser::setFilter); m_extensionBrowser, &ExtensionsBrowser::setFilter);
updateView({}); updateView({});
} }
ExtensionManagerWidget::~ExtensionManagerWidget()
{
delete d;
}
void ExtensionManagerWidget::updateView(const QModelIndex &current) void ExtensionManagerWidget::updateView(const QModelIndex &current)
{ {
d->headingWidget->update(current); m_headingWidget->update(current);
const bool showContent = current.isValid(); const bool showContent = current.isValid();
d->primaryContent->setVisible(showContent); m_primaryContent->setVisible(showContent);
d->secondaryContent->setVisible(showContent); m_secondaryContent->setVisible(showContent);
d->headingWidget->setVisible(showContent); m_headingWidget->setVisible(showContent);
d->pluginStatus->setVisible(showContent); m_pluginStatus->setVisible(showContent);
if (!showContent) if (!showContent)
return; return;
d->currentItemName = current.data().toString(); m_currentItemName = current.data().toString();
const bool isPack = current.data(RoleItemType) == ItemTypePack; const bool isPack = current.data(RoleItemType) == ItemTypePack;
d->pluginStatus->setPluginName(isPack ? QString() : d->currentItemName); m_pluginStatus->setPluginName(isPack ? QString() : m_currentItemName);
d->currentItemPlugins = current.data(RolePlugins).value<PluginsData>(); m_currentItemPlugins = current.data(RolePlugins).value<PluginsData>();
auto toContentParagraph = [](const QString &text) { auto toContentParagraph = [](const QString &text) {
const QString pHtml = QString::fromLatin1("<p style=\"margin-top:0;margin-bottom:0;" const QString pHtml = QString::fromLatin1("<p style=\"margin-top:0;margin-bottom:0;"
@@ -592,9 +592,9 @@ void ExtensionManagerWidget::updateView(const QModelIndex &current)
descriptionHtml.prepend(QString::fromLatin1("<body style=\"color:%1;\">") descriptionHtml.prepend(QString::fromLatin1("<body style=\"color:%1;\">")
.arg(creatorColor(Theme::Token_Text_Default).name())); .arg(creatorColor(Theme::Token_Text_Default).name()));
descriptionHtml.append("</body>"); descriptionHtml.append("</body>");
d->description->setText(descriptionHtml); m_description->setText(descriptionHtml);
} }
d->description->setVisible(hasDescription); m_description->setVisible(hasDescription);
const LinksData linksData = current.data(RoleDescriptionLinks).value<LinksData>(); const LinksData linksData = current.data(RoleDescriptionLinks).value<LinksData>();
const bool hasLinks = !linksData.isEmpty(); const bool hasLinks = !linksData.isEmpty();
@@ -608,55 +608,55 @@ void ExtensionManagerWidget::updateView(const QModelIndex &current)
.arg(anchor); .arg(anchor);
}); });
linksHtml = links.join("<br/>"); linksHtml = links.join("<br/>");
d->links->setText(toContentParagraph(linksHtml)); m_links->setText(toContentParagraph(linksHtml));
} }
d->linksTitle->setVisible(hasLinks); m_linksTitle->setVisible(hasLinks);
d->links->setVisible(hasLinks); m_links->setVisible(hasLinks);
d->imgTaskTreeRunner.reset(); m_imgTaskTreeRunner.reset();
d->imageMovie.stop(); m_imageMovie.stop();
d->imageDataBuffer.close(); m_imageDataBuffer.close();
d->image->clear(); m_image->clear();
const ImagesData imagesData = current.data(RoleDescriptionImages).value<ImagesData>(); const ImagesData imagesData = current.data(RoleDescriptionImages).value<ImagesData>();
const bool hasImages = !imagesData.isEmpty(); const bool hasImages = !imagesData.isEmpty();
if (hasImages) { if (hasImages) {
const ImagesData::Type &image = imagesData.constFirst(); // Only show one image const ImagesData::Type &image = imagesData.constFirst(); // Only show one image
d->imageTitle->setText(image.first); m_imageTitle->setText(image.first);
fetchAndDisplayImage(image.second); fetchAndDisplayImage(image.second);
} }
d->imageTitle->setVisible(hasImages); m_imageTitle->setVisible(hasImages);
d->image->setVisible(hasImages); m_image->setVisible(hasImages);
} }
{ {
const QStringList tags = current.data(RoleTags).toStringList(); const QStringList tags = current.data(RoleTags).toStringList();
d->tags->setTags(tags); m_tags->setTags(tags);
const bool hasTags = !tags.isEmpty(); const bool hasTags = !tags.isEmpty();
d->tagsTitle->setVisible(hasTags); m_tagsTitle->setVisible(hasTags);
d->tags->setVisible(hasTags); m_tags->setVisible(hasTags);
const QStringList platforms = current.data(RolePlatforms).toStringList(); const QStringList platforms = current.data(RolePlatforms).toStringList();
const bool hasPlatforms = !platforms.isEmpty(); const bool hasPlatforms = !platforms.isEmpty();
if (hasPlatforms) if (hasPlatforms)
d->platforms->setText(toContentParagraph(platforms.join("<br/>"))); m_platforms->setText(toContentParagraph(platforms.join("<br/>")));
d->platformsTitle->setVisible(hasPlatforms); m_platformsTitle->setVisible(hasPlatforms);
d->platforms->setVisible(hasPlatforms); m_platforms->setVisible(hasPlatforms);
const QStringList dependencies = current.data(RoleDependencies).toStringList(); const QStringList dependencies = current.data(RoleDependencies).toStringList();
const bool hasDependencies = !dependencies.isEmpty(); const bool hasDependencies = !dependencies.isEmpty();
if (hasDependencies) if (hasDependencies)
d->dependencies->setText(toContentParagraph(dependencies.join("<br/>"))); m_dependencies->setText(toContentParagraph(dependencies.join("<br/>")));
d->dependenciesTitle->setVisible(hasDependencies); m_dependenciesTitle->setVisible(hasDependencies);
d->dependencies->setVisible(hasDependencies); m_dependencies->setVisible(hasDependencies);
const PluginsData plugins = current.data(RolePlugins).value<PluginsData>(); const PluginsData plugins = current.data(RolePlugins).value<PluginsData>();
const bool hasExtensions = isPack && !plugins.isEmpty(); const bool hasExtensions = isPack && !plugins.isEmpty();
if (hasExtensions) { if (hasExtensions) {
const QStringList extensions = transform(plugins, &QPair<QString, QString>::first); const QStringList extensions = transform(plugins, &QPair<QString, QString>::first);
d->packExtensions->setText(toContentParagraph(extensions.join("<br/>"))); m_packExtensions->setText(toContentParagraph(extensions.join("<br/>")));
} }
d->packExtensionsTitle->setVisible(hasExtensions); m_packExtensionsTitle->setVisible(hasExtensions);
d->packExtensions->setVisible(hasExtensions); m_packExtensions->setVisible(hasExtensions);
} }
} }
@@ -717,7 +717,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url)
onGroupDone(onPluginInstallation), onGroupDone(onPluginInstallation),
}; };
d->dlTaskTreeRunner.start(group); m_dlTaskTreeRunner.start(group);
} }
void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url) void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url)
@@ -744,17 +744,17 @@ void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url)
const auto onShowImage = [storage, this]() { const auto onShowImage = [storage, this]() {
if (storage->imageData.isEmpty()) if (storage->imageData.isEmpty())
return; return;
d->imageDataBuffer.setData(storage->imageData); m_imageDataBuffer.setData(storage->imageData);
if (!d->imageDataBuffer.open(QIODevice::ReadOnly)) if (!m_imageDataBuffer.open(QIODevice::ReadOnly))
return; return;
QImageReader reader(&d->imageDataBuffer); QImageReader reader(&m_imageDataBuffer);
const bool animated = reader.supportsAnimation(); const bool animated = reader.supportsAnimation();
if (animated) { if (animated) {
d->image->setMovie(&d->imageMovie); m_image->setMovie(&m_imageMovie);
d->imageMovie.start(); m_imageMovie.start();
} else { } else {
const QPixmap pixmap = QPixmap::fromImage(reader.read()); const QPixmap pixmap = QPixmap::fromImage(reader.read());
d->image->setPixmap(pixmap); m_image->setPixmap(pixmap);
} }
}; };
@@ -764,7 +764,12 @@ void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url)
onGroupDone(onShowImage), onGroupDone(onShowImage),
}; };
d->imgTaskTreeRunner.start(group); m_imgTaskTreeRunner.start(group);
}
QWidget *createExtensionManagerWidget()
{
return new ExtensionManagerWidget;
} }
} // ExtensionManager::Internal } // ExtensionManager::Internal

View File

@@ -1,22 +1,10 @@
// Copyright (C) 2023 The Qt Company Ltd. // Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <coreplugin/welcomepagehelper.h> #include <QWidget>
namespace ExtensionManager::Internal { namespace ExtensionManager::Internal {
class ExtensionManagerWidget final : public Core::ResizeSignallingWidget QWidget *createExtensionManagerWidget();
{
public:
explicit ExtensionManagerWidget(QWidget *parent = nullptr);
~ExtensionManagerWidget();
private:
void updateView(const QModelIndex &current);
void fetchAndInstallPlugin(const QUrl &url);
void fetchAndDisplayImage(const QUrl &url);
class ExtensionManagerWidgetPrivate *d = nullptr;
};
} // ExtensionManager::Internal } // ExtensionManager::Internal