forked from qt-creator/qt-creator
Add Qt Marketplace plugin
Provides a simple integration into the welcome page. Task-number: QTCREATORBUG-23452 Change-Id: I3e615dcd6dfd9e401159ea6d30b48737edb1e1f9 Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -6,6 +6,7 @@ add_subdirectory(texteditor)
|
||||
add_subdirectory(serialterminal)
|
||||
add_subdirectory(helloworld)
|
||||
add_subdirectory(imageviewer)
|
||||
add_subdirectory(marketplace)
|
||||
add_subdirectory(updateinfo)
|
||||
add_subdirectory(welcome)
|
||||
|
||||
|
7
src/plugins/marketplace/CMakeLists.txt
Normal file
7
src/plugins/marketplace/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
add_qtc_plugin(Marketplace
|
||||
PLUGIN_DEPENDS Core
|
||||
SOURCES
|
||||
marketplaceplugin.h
|
||||
productlistmodel.cpp productlistmodel.h
|
||||
qtmarketplacewelcomepage.cpp qtmarketplacewelcomepage.h
|
||||
)
|
18
src/plugins/marketplace/Marketplace.json.in
Normal file
18
src/plugins/marketplace/Marketplace.json.in
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
\"Name\" : \"Marketplace\",
|
||||
\"Version\" : \"$$QTCREATOR_VERSION\",
|
||||
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
|
||||
\"Vendor\" : \"The Qt Company Ltd\",
|
||||
\"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
|
||||
\"License\" : [ \"Commercial Usage\",
|
||||
\"\",
|
||||
\"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\",
|
||||
\"\",
|
||||
\"GNU General Public License Usage\",
|
||||
\"\",
|
||||
\"Alternatively, this file may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this file. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
|
||||
],
|
||||
\"Description\" : \"Qt Marketplace plugin.\",
|
||||
\"Url\" : \"http://www.qt.io\",
|
||||
$$dependencyList
|
||||
}
|
16
src/plugins/marketplace/marketplace.pro
Normal file
16
src/plugins/marketplace/marketplace.pro
Normal file
@@ -0,0 +1,16 @@
|
||||
TARGET = Marketplace
|
||||
TEMPLATE = lib
|
||||
QT += network
|
||||
|
||||
include(../../qtcreatorplugin.pri)
|
||||
|
||||
DEFINES += MARKETPLACE_LIBRARY
|
||||
|
||||
SOURCES += \
|
||||
productlistmodel.cpp \
|
||||
qtmarketplacewelcomepage.cpp
|
||||
|
||||
HEADERS += \
|
||||
marketplaceplugin.h \
|
||||
productlistmodel.h \
|
||||
qtmarketplacewelcomepage.h
|
17
src/plugins/marketplace/marketplace.qbs
Normal file
17
src/plugins/marketplace/marketplace.qbs
Normal file
@@ -0,0 +1,17 @@
|
||||
import qbs
|
||||
|
||||
QtcPlugin {
|
||||
name: "Marketplace"
|
||||
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "Utils" }
|
||||
|
||||
Depends { name: "Qt.widgets" }
|
||||
Depends { name: "Qt.network" }
|
||||
|
||||
files: [
|
||||
"marketplaceplugin.h",
|
||||
"productlistmodel.cpp", "productlistmodel.h",
|
||||
"qtmarketplacewelcomepage.cpp", "qtmarketplacewelcomepage.h",
|
||||
]
|
||||
}
|
7
src/plugins/marketplace/marketplace_dependencies.pri
Normal file
7
src/plugins/marketplace/marketplace_dependencies.pri
Normal file
@@ -0,0 +1,7 @@
|
||||
QTC_PLUGIN_NAME = Marketplace
|
||||
|
||||
QTC_PLUGIN_DEPENDS += \
|
||||
coreplugin
|
||||
|
||||
QTC_LIB_DEPENDS += \
|
||||
utils
|
49
src/plugins/marketplace/marketplaceplugin.h
Normal file
49
src/plugins/marketplace/marketplaceplugin.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include "qtmarketplacewelcomepage.h"
|
||||
|
||||
namespace Marketplace {
|
||||
|
||||
class MarketplacePlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Marketplace.json")
|
||||
|
||||
public:
|
||||
MarketplacePlugin() = default;
|
||||
|
||||
bool initialize(const QStringList &, QString *) final { return true; }
|
||||
void extensionsInitialized() final {}
|
||||
|
||||
private:
|
||||
Internal::QtMarketplaceWelcomePage welcomePage;
|
||||
};
|
||||
|
||||
} // namespace Marketplace
|
250
src/plugins/marketplace/productlistmodel.cpp
Normal file
250
src/plugins/marketplace/productlistmodel.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "productlistmodel.h"
|
||||
|
||||
#include "marketplaceplugin.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/executeondestruction.h>
|
||||
#include <utils/networkaccessmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPixmapCache>
|
||||
#include <QRegularExpression>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
|
||||
namespace Marketplace {
|
||||
namespace Internal {
|
||||
|
||||
static const QNetworkRequest constructRequest(const QString &collection)
|
||||
{
|
||||
QString url("https://marketplace.qt.io");
|
||||
if (collection.isEmpty())
|
||||
url.append("/collections.json");
|
||||
else
|
||||
url.append("/collections/").append(collection).append("/products.json");
|
||||
|
||||
return QNetworkRequest(url);
|
||||
}
|
||||
|
||||
static const QString plainTextFromHtml(const QString &original)
|
||||
{
|
||||
QString plainText(original);
|
||||
QRegularExpression breakReturn("<\\s*br/?\\s*>", QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
plainText.replace(breakReturn, "\n"); // "translate" <br/> into newline
|
||||
plainText.remove(QRegularExpression("<[^>]*>")); // remove all tags
|
||||
plainText = plainText.trimmed();
|
||||
plainText.replace(QRegularExpression("\n{3,}"), "\n\n"); // consolidate some newlines
|
||||
|
||||
// FIXME the description text is usually too long and needs to get elided sensibly
|
||||
return (plainText.length() > 157) ? plainText.left(157).append("...") : plainText;
|
||||
}
|
||||
|
||||
ProductListModel::ProductListModel(QObject *parent)
|
||||
: Core::ListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ProductListModel::updateCollections()
|
||||
{
|
||||
emit toggleProgressIndicator(true);
|
||||
QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(constructRequest({}));
|
||||
connect(reply, &QNetworkReply::finished,
|
||||
this, [this, reply]() { onFetchCollectionsFinished(reply); });
|
||||
}
|
||||
|
||||
QPixmap ProductListModel::fetchPixmapAndUpdatePixmapCache(const QString &url) const
|
||||
{
|
||||
const_cast<ProductListModel *>(this)->queueImageForDownload(url);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void ProductListModel::onFetchCollectionsFinished(QNetworkReply *reply)
|
||||
{
|
||||
QTC_ASSERT(reply, return);
|
||||
Utils::ExecuteOnDestruction replyDeleter([reply]() { reply->deleteLater(); });
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
|
||||
if (doc.isNull())
|
||||
return;
|
||||
|
||||
const QJsonArray collections = doc.object().value("collections").toArray();
|
||||
for (int i = 0, end = collections.size(); i < end; ++i) {
|
||||
const QJsonObject obj = collections.at(i).toObject();
|
||||
const auto handle = obj.value("handle").toString();
|
||||
const int productsCount = obj.value("products_count").toInt();
|
||||
|
||||
if (productsCount > 0 && handle != "all-products")
|
||||
m_pendingCollections.append(handle);
|
||||
}
|
||||
if (!m_pendingCollections.isEmpty())
|
||||
fetchCollectionsContents();
|
||||
} else {
|
||||
QVariant status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
if (status.isValid() && status.toInt() == 430)
|
||||
QTimer::singleShot(30000, this, &ProductListModel::updateCollections);
|
||||
else
|
||||
emit errorOccurred(reply->error(), reply->errorString());
|
||||
}
|
||||
}
|
||||
|
||||
void ProductListModel::onFetchSingleCollectionFinished(QNetworkReply *reply)
|
||||
{
|
||||
emit toggleProgressIndicator(false);
|
||||
|
||||
QTC_ASSERT(reply, return);
|
||||
Utils::ExecuteOnDestruction replyDeleter([reply]() { reply->deleteLater(); });
|
||||
|
||||
QList<Core::ListItem *> productsForCollection;
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
|
||||
if (doc.isNull())
|
||||
return;
|
||||
|
||||
const QJsonArray products = doc.object().value("products").toArray();
|
||||
for (int i = 0, end = products.size(); i < end; ++i) {
|
||||
const QJsonObject obj = products.at(i).toObject();
|
||||
const QString handle = obj.value("handle").toString();
|
||||
|
||||
bool foundItem = Utils::findOrDefault(m_items, [handle](const Core::ListItem *it) {
|
||||
return static_cast<const ProductItem *>(it)->handle == handle;
|
||||
});
|
||||
if (foundItem)
|
||||
continue;
|
||||
|
||||
ProductItem *product = new ProductItem;
|
||||
product->name = obj.value("title").toString();
|
||||
product->description = plainTextFromHtml(obj.value("body_html").toString());
|
||||
|
||||
product->handle = handle;
|
||||
for (auto val : obj.value("tags").toArray())
|
||||
product->tags.append(val.toString());
|
||||
|
||||
const auto images = obj.value("images").toArray();
|
||||
if (!images.isEmpty()) {
|
||||
auto imgObj = images.first().toObject();
|
||||
const QJsonValue imageSrc = imgObj.value("src");
|
||||
if (imageSrc.isString())
|
||||
product->imageUrl = imageSrc.toString();
|
||||
}
|
||||
|
||||
productsForCollection.append(product);
|
||||
}
|
||||
|
||||
if (!productsForCollection.isEmpty()) {
|
||||
beginInsertRows(QModelIndex(), m_items.size(), m_items.size() + productsForCollection.size());
|
||||
m_items.append(productsForCollection);
|
||||
endInsertRows();
|
||||
}
|
||||
} else {
|
||||
// bad.. but we still might be able to fetch another collection
|
||||
qWarning() << "Failed to fetch collection:" << reply->errorString() << reply->error();
|
||||
}
|
||||
|
||||
if (!m_pendingCollections.isEmpty()) // more collections? go ahead..
|
||||
fetchCollectionsContents();
|
||||
else if (m_items.isEmpty())
|
||||
emit errorOccurred(0, "Failed to fetch any collection.");
|
||||
}
|
||||
|
||||
void ProductListModel::fetchCollectionsContents()
|
||||
{
|
||||
QTC_ASSERT(!m_pendingCollections.isEmpty(), return);
|
||||
const QString collection = m_pendingCollections.dequeue();
|
||||
|
||||
QNetworkReply *reply
|
||||
= Utils::NetworkAccessManager::instance()->get(constructRequest(collection));
|
||||
connect(reply, &QNetworkReply::finished,
|
||||
this, [this, reply]() { onFetchSingleCollectionFinished(reply); });
|
||||
}
|
||||
|
||||
void ProductListModel::queueImageForDownload(const QString &url)
|
||||
{
|
||||
m_pendingImages.insert(url);
|
||||
if (!m_isDownloadingImage)
|
||||
fetchNextImage();
|
||||
}
|
||||
|
||||
void ProductListModel::fetchNextImage()
|
||||
{
|
||||
if (m_pendingImages.isEmpty()) {
|
||||
m_isDownloadingImage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto it = m_pendingImages.begin();
|
||||
const QString nextUrl = *it;
|
||||
m_pendingImages.erase(it);
|
||||
|
||||
if (QPixmapCache::find(nextUrl, nullptr)) { // this image is already cached
|
||||
updateModelIndexesForUrl(nextUrl); // it might have been added while downloading
|
||||
fetchNextImage();
|
||||
return;
|
||||
}
|
||||
|
||||
m_isDownloadingImage = true;
|
||||
QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(QNetworkRequest(nextUrl));
|
||||
connect(reply, &QNetworkReply::finished,
|
||||
this, [this, reply]() { onImageDownloadFinished(reply); });
|
||||
}
|
||||
|
||||
void ProductListModel::onImageDownloadFinished(QNetworkReply *reply)
|
||||
{
|
||||
QTC_ASSERT(reply, return);
|
||||
Utils::ExecuteOnDestruction replyDeleter([reply]() { reply->deleteLater(); });
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QByteArray data = reply->readAll();
|
||||
QPixmap pixmap;
|
||||
if (pixmap.loadFromData(data)) {
|
||||
const QString url = reply->request().url().toString();
|
||||
QPixmapCache::insert(url, pixmap.scaled(ProductListModel::defaultImageSize,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
updateModelIndexesForUrl(url);
|
||||
}
|
||||
} // handle error not needed - it's okay'ish to have no images as long as the rest works
|
||||
|
||||
fetchNextImage();
|
||||
}
|
||||
|
||||
void ProductListModel::updateModelIndexesForUrl(const QString &url)
|
||||
{
|
||||
for (int row = 0, end = m_items.size(); row < end; ++row) {
|
||||
if (m_items.at(row)->imageUrl == url)
|
||||
emit dataChanged(index(row), index(row), {ItemImageRole, Qt::DisplayRole});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Marketplace
|
77
src/plugins/marketplace/productlistmodel.h
Normal file
77
src/plugins/marketplace/productlistmodel.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <coreplugin/welcomepagehelper.h>
|
||||
|
||||
#include <QQueue>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QNetworkReply;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Marketplace {
|
||||
namespace Internal {
|
||||
|
||||
class ProductItem : public Core::ListItem
|
||||
{
|
||||
public:
|
||||
QString handle;
|
||||
};
|
||||
|
||||
class ProductListModel : public Core::ListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProductListModel(QObject *parent);
|
||||
void updateCollections();
|
||||
|
||||
signals:
|
||||
void errorOccurred(int errorCode, const QString &errorString);
|
||||
void toggleProgressIndicator(bool show);
|
||||
|
||||
protected:
|
||||
QPixmap fetchPixmapAndUpdatePixmapCache(const QString &url) const override;
|
||||
|
||||
private:
|
||||
void onFetchCollectionsFinished(QNetworkReply *reply);
|
||||
void onFetchSingleCollectionFinished(QNetworkReply *reply);
|
||||
void fetchCollectionsContents();
|
||||
|
||||
void queueImageForDownload(const QString &url);
|
||||
void fetchNextImage();
|
||||
void onImageDownloadFinished(QNetworkReply *reply);
|
||||
void updateModelIndexesForUrl(const QString &url);
|
||||
|
||||
QQueue<QString> m_pendingCollections;
|
||||
QSet<QString> m_pendingImages;
|
||||
bool m_isDownloadingImage = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Marketplace
|
||||
|
||||
Q_DECLARE_METATYPE(Marketplace::Internal::ProductItem *)
|
178
src/plugins/marketplace/qtmarketplacewelcomepage.cpp
Normal file
178
src/plugins/marketplace/qtmarketplacewelcomepage.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtmarketplacewelcomepage.h"
|
||||
|
||||
#include "productlistmodel.h"
|
||||
|
||||
#include <coreplugin/welcomepagehelper.h>
|
||||
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/progressindicator.h>
|
||||
#include <utils/theme/theme.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QShowEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace Marketplace {
|
||||
namespace Internal {
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
QString QtMarketplaceWelcomePage::title() const
|
||||
{
|
||||
return tr("Marketplace");
|
||||
}
|
||||
|
||||
int QtMarketplaceWelcomePage::priority() const
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
||||
Core::Id QtMarketplaceWelcomePage::id() const
|
||||
{
|
||||
return "Marketplace";
|
||||
}
|
||||
|
||||
class ProductItemDelegate : public Core::ListItemDelegate
|
||||
{
|
||||
public:
|
||||
void clickAction(const Core::ListItem *item) const override
|
||||
{
|
||||
QTC_ASSERT(item, return);
|
||||
auto productItem = static_cast<const ProductItem *>(item);
|
||||
const QUrl url(QString("https://marketplace.qt.io/products/").append(productItem->handle));
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
};
|
||||
|
||||
class QtMarketplacePageWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
QtMarketplacePageWidget()
|
||||
: m_productModel(new ProductListModel(this))
|
||||
{
|
||||
const int sideMargin = 27;
|
||||
auto filteredModel = new Core::ListModelFilter(m_productModel, this);
|
||||
|
||||
auto searchBox = new Core::SearchBox(this);
|
||||
m_searcher = searchBox->m_lineEdit;
|
||||
m_searcher->setPlaceholderText(QtMarketplaceWelcomePage::tr("Search in Marketplace..."));
|
||||
|
||||
auto vbox = new QVBoxLayout(this);
|
||||
vbox->setContentsMargins(30, sideMargin, 0, 0);
|
||||
|
||||
auto hbox = new QHBoxLayout;
|
||||
hbox->addWidget(searchBox);
|
||||
hbox->addSpacing(sideMargin);
|
||||
vbox->addItem(hbox);
|
||||
m_errorLabel = new QLabel(this);
|
||||
m_errorLabel->setVisible(false);
|
||||
vbox->addWidget(m_errorLabel);
|
||||
|
||||
m_gridModel.setSourceModel(filteredModel);
|
||||
|
||||
auto gridView = new Core::GridView(this);
|
||||
gridView->setModel(&m_gridModel);
|
||||
gridView->setItemDelegate(&m_productDelegate);
|
||||
vbox->addWidget(gridView);
|
||||
|
||||
auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this);
|
||||
progressIndicator->attachToWidget(gridView);
|
||||
progressIndicator->hide();
|
||||
|
||||
connect(m_productModel, &ProductListModel::toggleProgressIndicator,
|
||||
progressIndicator, &Utils::ProgressIndicator::setVisible);
|
||||
connect(m_productModel, &ProductListModel::errorOccurred,
|
||||
[this, searchBox](int, const QString &message) {
|
||||
m_errorLabel->setAlignment(Qt::AlignHCenter);
|
||||
QFont f(m_errorLabel->font());
|
||||
f.setPixelSize(20);
|
||||
m_errorLabel->setFont(f);
|
||||
const QString txt
|
||||
= QtMarketplaceWelcomePage::tr(
|
||||
"<p>Could not fetch data from Qt Marketplace.</p><p>Try with your browser "
|
||||
"instead: <a href='https://marketplace.qt.io'>https://marketplace.qt.io</a>"
|
||||
"</p><br/><p><small><i>Error: %1</i></small></p>").arg(message);
|
||||
m_errorLabel->setText(txt);
|
||||
m_errorLabel->setVisible(true);
|
||||
searchBox->setVisible(false);
|
||||
connect(m_errorLabel, &QLabel::linkActivated,
|
||||
this, []() { QDesktopServices::openUrl(QUrl("https://marketplace.qt.io")); });
|
||||
});
|
||||
connect(&m_productDelegate, &ProductItemDelegate::tagClicked,
|
||||
this, &QtMarketplacePageWidget::onTagClicked);
|
||||
connect(m_searcher, &QLineEdit::textChanged,
|
||||
filteredModel, &Core::ListModelFilter::setSearchString);
|
||||
}
|
||||
|
||||
void showEvent(QShowEvent *event) override
|
||||
{
|
||||
if (!m_initialized) {
|
||||
m_initialized = true;
|
||||
m_productModel->updateCollections();
|
||||
}
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent *ev) final
|
||||
{
|
||||
QWidget::resizeEvent(ev);
|
||||
m_gridModel.setColumnCount(bestColumnCount());
|
||||
}
|
||||
|
||||
int bestColumnCount() const
|
||||
{
|
||||
return qMax(1, width() / (Core::GridProxyModel::GridItemWidth
|
||||
+ Core::GridProxyModel::GridItemGap));
|
||||
}
|
||||
|
||||
void onTagClicked(const QString &tag)
|
||||
{
|
||||
QString text = m_searcher->text();
|
||||
m_searcher->setText(text + QString("tag:\"%1\" ").arg(tag));
|
||||
}
|
||||
|
||||
private:
|
||||
ProductItemDelegate m_productDelegate;
|
||||
ProductListModel *m_productModel = nullptr;
|
||||
QLabel *m_errorLabel = nullptr;
|
||||
QLineEdit *m_searcher = nullptr;
|
||||
Core::GridProxyModel m_gridModel;
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
|
||||
QWidget *QtMarketplaceWelcomePage::createWidget() const
|
||||
{
|
||||
return new QtMarketplacePageWidget;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Marketplace
|
48
src/plugins/marketplace/qtmarketplacewelcomepage.h
Normal file
48
src/plugins/marketplace/qtmarketplacewelcomepage.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <coreplugin/iwelcomepage.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace Marketplace {
|
||||
namespace Internal {
|
||||
|
||||
class QtMarketplaceWelcomePage : public Core::IWelcomePage
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Marketplace::Internal::QtMarketplaceWelcomePage)
|
||||
public:
|
||||
QtMarketplaceWelcomePage() = default;
|
||||
|
||||
QString title() const final;
|
||||
int priority() const final;
|
||||
Core::Id id() const final;
|
||||
QWidget *createWidget() const final;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Marketplace
|
@@ -63,7 +63,8 @@ SUBDIRS = \
|
||||
qmlpreview \
|
||||
studiowelcome \
|
||||
webassembly \
|
||||
mcusupport
|
||||
mcusupport \
|
||||
marketplace
|
||||
|
||||
qtHaveModule(serialport) {
|
||||
SUBDIRS += serialterminal
|
||||
|
@@ -46,6 +46,7 @@ Project {
|
||||
"ios/ios.qbs",
|
||||
"languageclient/languageclient.qbs",
|
||||
"macros/macros.qbs",
|
||||
"marketplace/marketplace.qbs",
|
||||
"mcusupport/mcusupport.qbs",
|
||||
"mercurial/mercurial.qbs",
|
||||
"modeleditor/modeleditor.qbs",
|
||||
|
Reference in New Issue
Block a user