forked from qt-creator/qt-creator
Plugins: Add skeleton for new ExtensionManager plugin
This initial commit is merely a mockup of a ExtensionManager concept. Change-Id: I19b2285667678a86097c043cc27a554545559eff Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
305
src/plugins/extensionmanager/extensionmanagerwidget.cpp
Normal file
305
src/plugins/extensionmanager/extensionmanagerwidget.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "extensionmanagertr.h"
|
||||
|
||||
#include "extensionmanagerconstants.h"
|
||||
#include "extensionmanagerwidget.h"
|
||||
#include "extensionsbrowser.h"
|
||||
#include "utils/algorithm.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/icontext.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/iwelcomepage.h>
|
||||
#include <coreplugin/modemanager.h> // TODO: Remove!
|
||||
#include <coreplugin/welcomepagehelper.h>
|
||||
|
||||
#include <extensionsystem/pluginspec.h>
|
||||
|
||||
#include <utils/icon.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QTextBrowser>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Utils;
|
||||
|
||||
namespace ExtensionManager::Internal {
|
||||
|
||||
static QWidget *createVr(QWidget *parent = nullptr)
|
||||
{
|
||||
auto vr = new QWidget(parent);
|
||||
vr->setFixedWidth(1);
|
||||
setBackgroundColor(vr, Theme::Token_Stroke_Subtle);
|
||||
return vr;
|
||||
}
|
||||
|
||||
class CollapsingWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit CollapsingWidget(QWidget *parent = nullptr)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
|
||||
}
|
||||
|
||||
void setWidth(int width)
|
||||
{
|
||||
m_width = width;
|
||||
setVisible(width > 0);
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
return {m_width, 0};
|
||||
}
|
||||
|
||||
private:
|
||||
int m_width = 100;
|
||||
};
|
||||
|
||||
ExtensionManagerWidget::ExtensionManagerWidget()
|
||||
{
|
||||
m_leftColumn = new ExtensionsBrowser;
|
||||
|
||||
auto descriptionColumns = new QWidget;
|
||||
|
||||
m_secondarDescriptionWidget = new CollapsingWidget;
|
||||
|
||||
m_primaryDescription = new QTextBrowser;
|
||||
m_primaryDescription->setOpenExternalLinks(true);
|
||||
m_primaryDescription->setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
m_secondaryDescription = new QTextBrowser;
|
||||
m_secondaryDescription->setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
using namespace Layouting;
|
||||
Row {
|
||||
createVr(),
|
||||
m_secondaryDescription,
|
||||
noMargin(), spacing(0),
|
||||
}.attachTo(m_secondarDescriptionWidget);
|
||||
|
||||
Row {
|
||||
createVr(),
|
||||
Row {
|
||||
m_primaryDescription,
|
||||
noMargin(),
|
||||
},
|
||||
m_secondarDescriptionWidget,
|
||||
noMargin(), spacing(0),
|
||||
}.attachTo(descriptionColumns);
|
||||
|
||||
Row {
|
||||
Space(WelcomePageHelpers::HSpacing),
|
||||
m_leftColumn,
|
||||
descriptionColumns,
|
||||
noMargin(), spacing(0),
|
||||
}.attachTo(this);
|
||||
|
||||
setBackgroundColor(this, Theme::Token_Background_Default);
|
||||
|
||||
connect(m_leftColumn, &ExtensionsBrowser::itemSelected,
|
||||
this, &ExtensionManagerWidget::updateView);
|
||||
connect(this, &ResizeSignallingWidget::resized, this,
|
||||
[this] (const QSize &size, const QSize &oldSize) {
|
||||
const int intendedLeftColumnWidth = size.width() - 580;
|
||||
m_leftColumn->adjustToWidth(intendedLeftColumnWidth);
|
||||
const bool secondaryDescriptionVisible = size.width() > 970;
|
||||
const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0;
|
||||
m_secondarDescriptionWidget->setWidth(secondaryDescriptionWidth);
|
||||
});
|
||||
updateView({}, {});
|
||||
}
|
||||
|
||||
void ExtensionManagerWidget::updateView(const QModelIndex ¤t,
|
||||
[[maybe_unused]] const QModelIndex &previous)
|
||||
{
|
||||
const QString h5Css =
|
||||
StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH5))
|
||||
+ "; margin-top: 28px;";
|
||||
const QString h6Css =
|
||||
StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6))
|
||||
+ "; margin-top: 28px;";
|
||||
const QString h6CapitalCss =
|
||||
StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6Capital))
|
||||
+ QString::fromLatin1("; color: %1;")
|
||||
.arg(creatorTheme()->color(Theme::Token_Text_Muted).name());
|
||||
const QString bodyStyle = QString::fromLatin1("color: %1; background-color: %2;"
|
||||
"margin-left: %3px; margin-right: %3px;")
|
||||
.arg(creatorTheme()->color(Theme::Token_Text_Default).name())
|
||||
.arg(creatorTheme()->color(Theme::Token_Background_Muted).name())
|
||||
.arg(WelcomePageHelpers::HSpacing);
|
||||
const QString htmlStart = QString(R"(
|
||||
<html>
|
||||
<body style="%1">
|
||||
)").arg(bodyStyle);
|
||||
const QString htmlEnd = QString(R"(
|
||||
</body></html>
|
||||
)");
|
||||
|
||||
if (!current.isValid()) {
|
||||
const QString emptyHtml = htmlStart + htmlEnd;
|
||||
m_primaryDescription->setText(emptyHtml);
|
||||
m_secondaryDescription->setText(emptyHtml);
|
||||
return;
|
||||
}
|
||||
|
||||
const ItemData data = itemData(current);
|
||||
const bool isPack = data.type == ItemTypePack;
|
||||
const ExtensionSystem::PluginSpec *extension = data.plugins.first();
|
||||
|
||||
{
|
||||
const QString shortDescription =
|
||||
isPack ? QLatin1String("Short description for pack ") + data.name
|
||||
: extension->description();
|
||||
QString longDescription =
|
||||
isPack ? QLatin1String("Some longer text that describes the purpose and functionality "
|
||||
"of the extensions that are part of pack ") + data.name
|
||||
: extension->longDescription();
|
||||
longDescription.replace("\n", "<br/>");
|
||||
const QString location = isPack ? extension->location() : extension->filePath();
|
||||
|
||||
QString description = htmlStart;
|
||||
|
||||
description.append(QString(R"(
|
||||
<div style="%1"><br/>%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h5Css)
|
||||
.arg(shortDescription)
|
||||
.arg(longDescription));
|
||||
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Get started"))
|
||||
.arg(Tr::tr("Install the extension from above. Installation starts automatically. "
|
||||
"You can always uninstall the extension afterwards.")));
|
||||
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>
|
||||
<a href="%3">%4 ></a>
|
||||
<br/>
|
||||
<a href="%5">%6 ></a>
|
||||
</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("More information"))
|
||||
.arg(Tr::tr("Online Documentation"))
|
||||
.arg("https://doc.qt.io/qtcreator/")
|
||||
.arg(Tr::tr("Tutorials"))
|
||||
.arg("https://doc.qt.io/qtcreator/creator-tutorials.html"));
|
||||
|
||||
const QString examplesBoxCss =
|
||||
QString::fromLatin1("height: 168px; background-color: %1; ")
|
||||
.arg(creatorTheme()->color(Theme::Token_Background_Default).name());
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p style="%3">
|
||||
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
|
||||
</p>
|
||||
)").arg(h6CapitalCss)
|
||||
.arg(Tr::tr("Examples"))
|
||||
.arg(examplesBoxCss));
|
||||
|
||||
const QString captionStrongCss = StyleHelper::fontToCssProperties(
|
||||
StyleHelper::uiFont(StyleHelper::UiElementCaptionStrong));
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>
|
||||
<table>
|
||||
<tr><td style="%3">%4</td><td>%5</td></tr>
|
||||
<tr><td style="%3">%6</td><td>%7</td></tr>
|
||||
<tr><td style="%3">%8</td><td>%9</td></tr>
|
||||
</table>
|
||||
</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Extension library details"))
|
||||
.arg(captionStrongCss)
|
||||
.arg(Tr::tr("Size"))
|
||||
.arg("547 MB")
|
||||
.arg(Tr::tr("Version"))
|
||||
.arg(extension->version())
|
||||
.arg(Tr::tr("Location"))
|
||||
.arg(location));
|
||||
|
||||
description.append(htmlEnd);
|
||||
m_primaryDescription->setText(description);
|
||||
}
|
||||
|
||||
{
|
||||
QString description = htmlStart;
|
||||
|
||||
description.append(QString(R"(
|
||||
<p style="%1"><br/>%2</p>
|
||||
)").arg(h6CapitalCss)
|
||||
.arg(Tr::tr("Extension details")));
|
||||
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Released"))
|
||||
.arg("23.5.2023"));
|
||||
|
||||
const QString tagTemplate = QString(R"(
|
||||
<td style="border: 1px solid %1; padding: 3px; ">%2</td>
|
||||
)").arg(creatorTheme()->color(Theme::Token_Stroke_Subtle).name());
|
||||
const QStringList tags = Utils::transform(data.tags,
|
||||
[&tagTemplate] (const QString &tag) {
|
||||
return tagTemplate.arg(tag);
|
||||
});
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Related tags"))
|
||||
.arg(tags.join(" ")));
|
||||
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>
|
||||
macOS<br/>
|
||||
Windows<br/>
|
||||
Linux
|
||||
</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Platforms")));
|
||||
|
||||
QStringList dependencies;
|
||||
for (const ExtensionSystem::PluginSpec *spec : data.plugins) {
|
||||
dependencies.append(Utils::transform(spec->dependencies(),
|
||||
&ExtensionSystem::PluginDependency::toString));
|
||||
}
|
||||
dependencies.removeDuplicates();
|
||||
dependencies.sort();
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Dependencies"))
|
||||
.arg(dependencies.isEmpty() ? "-" : dependencies.join("<br/>")));
|
||||
|
||||
if (isPack) {
|
||||
const QStringList extensions = Utils::transform(data.plugins,
|
||||
&ExtensionSystem::PluginSpec::name);
|
||||
description.append(QString(R"(
|
||||
<div style="%1">%2</div>
|
||||
<p>%3</p>
|
||||
)").arg(h6Css)
|
||||
.arg(Tr::tr("Exentsions in pack"))
|
||||
.arg(extensions.join("<br/>")));
|
||||
}
|
||||
|
||||
description.append(htmlEnd);
|
||||
m_secondaryDescription->setText(description);
|
||||
}
|
||||
}
|
||||
|
||||
} // ExtensionManager::Internal
|
||||
Reference in New Issue
Block a user