From bf7b16d9ca2da237b1eb915a7c2ff83bfa482d3a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 13 Jan 2020 13:35:00 +0100 Subject: [PATCH] Add Qt Marketplace plugin Provides a simple integration into the welcome page. Task-number: QTCREATORBUG-23452 Change-Id: I3e615dcd6dfd9e401159ea6d30b48737edb1e1f9 Reviewed-by: David Schulz Reviewed-by: Christian Stenger --- src/plugins/CMakeLists.txt | 1 + src/plugins/marketplace/CMakeLists.txt | 7 + src/plugins/marketplace/Marketplace.json.in | 18 ++ src/plugins/marketplace/marketplace.pro | 16 ++ src/plugins/marketplace/marketplace.qbs | 17 ++ .../marketplace/marketplace_dependencies.pri | 7 + src/plugins/marketplace/marketplaceplugin.h | 49 ++++ src/plugins/marketplace/productlistmodel.cpp | 250 ++++++++++++++++++ src/plugins/marketplace/productlistmodel.h | 77 ++++++ .../marketplace/qtmarketplacewelcomepage.cpp | 178 +++++++++++++ .../marketplace/qtmarketplacewelcomepage.h | 48 ++++ src/plugins/plugins.pro | 3 +- src/plugins/plugins.qbs | 1 + 13 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 src/plugins/marketplace/CMakeLists.txt create mode 100644 src/plugins/marketplace/Marketplace.json.in create mode 100644 src/plugins/marketplace/marketplace.pro create mode 100644 src/plugins/marketplace/marketplace.qbs create mode 100644 src/plugins/marketplace/marketplace_dependencies.pri create mode 100644 src/plugins/marketplace/marketplaceplugin.h create mode 100644 src/plugins/marketplace/productlistmodel.cpp create mode 100644 src/plugins/marketplace/productlistmodel.h create mode 100644 src/plugins/marketplace/qtmarketplacewelcomepage.cpp create mode 100644 src/plugins/marketplace/qtmarketplacewelcomepage.h diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 378b603aa2a..85aa9991e66 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -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) diff --git a/src/plugins/marketplace/CMakeLists.txt b/src/plugins/marketplace/CMakeLists.txt new file mode 100644 index 00000000000..f663bc95110 --- /dev/null +++ b/src/plugins/marketplace/CMakeLists.txt @@ -0,0 +1,7 @@ +add_qtc_plugin(Marketplace + PLUGIN_DEPENDS Core + SOURCES + marketplaceplugin.h + productlistmodel.cpp productlistmodel.h + qtmarketplacewelcomepage.cpp qtmarketplacewelcomepage.h +) diff --git a/src/plugins/marketplace/Marketplace.json.in b/src/plugins/marketplace/Marketplace.json.in new file mode 100644 index 00000000000..fd7e6b592cb --- /dev/null +++ b/src/plugins/marketplace/Marketplace.json.in @@ -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 +} diff --git a/src/plugins/marketplace/marketplace.pro b/src/plugins/marketplace/marketplace.pro new file mode 100644 index 00000000000..0717bd6eb69 --- /dev/null +++ b/src/plugins/marketplace/marketplace.pro @@ -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 diff --git a/src/plugins/marketplace/marketplace.qbs b/src/plugins/marketplace/marketplace.qbs new file mode 100644 index 00000000000..342ad65cf53 --- /dev/null +++ b/src/plugins/marketplace/marketplace.qbs @@ -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", + ] +} diff --git a/src/plugins/marketplace/marketplace_dependencies.pri b/src/plugins/marketplace/marketplace_dependencies.pri new file mode 100644 index 00000000000..9c6acc7f2d7 --- /dev/null +++ b/src/plugins/marketplace/marketplace_dependencies.pri @@ -0,0 +1,7 @@ +QTC_PLUGIN_NAME = Marketplace + +QTC_PLUGIN_DEPENDS += \ + coreplugin + +QTC_LIB_DEPENDS += \ + utils diff --git a/src/plugins/marketplace/marketplaceplugin.h b/src/plugins/marketplace/marketplaceplugin.h new file mode 100644 index 00000000000..f3b9b3302a1 --- /dev/null +++ b/src/plugins/marketplace/marketplaceplugin.h @@ -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 + +#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 diff --git a/src/plugins/marketplace/productlistmodel.cpp b/src/plugins/marketplace/productlistmodel.cpp new file mode 100644 index 00000000000..de00dcebd33 --- /dev/null +++ b/src/plugins/marketplace/productlistmodel.cpp @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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"
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(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 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(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 diff --git a/src/plugins/marketplace/productlistmodel.h b/src/plugins/marketplace/productlistmodel.h new file mode 100644 index 00000000000..032008d6f7d --- /dev/null +++ b/src/plugins/marketplace/productlistmodel.h @@ -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 + +#include + +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 m_pendingCollections; + QSet m_pendingImages; + bool m_isDownloadingImage = false; +}; + +} // namespace Internal +} // namespace Marketplace + +Q_DECLARE_METATYPE(Marketplace::Internal::ProductItem *) diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp new file mode 100644 index 00000000000..9e54b7b62f4 --- /dev/null +++ b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp @@ -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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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(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( + "

Could not fetch data from Qt Marketplace.

Try with your browser " + "instead: https://marketplace.qt.io" + "


Error: %1

").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 diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.h b/src/plugins/marketplace/qtmarketplacewelcomepage.h new file mode 100644 index 00000000000..dc7a0546c08 --- /dev/null +++ b/src/plugins/marketplace/qtmarketplacewelcomepage.h @@ -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 + +#include + +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 diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index c07b02b1050..8fb6d384ed8 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -63,7 +63,8 @@ SUBDIRS = \ qmlpreview \ studiowelcome \ webassembly \ - mcusupport + mcusupport \ + marketplace qtHaveModule(serialport) { SUBDIRS += serialterminal diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 806f2895a19..35b6cb8629d 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -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",