From 70764080fd2d936fd61728bf6d4c0786d97440ad Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 24 Feb 2021 21:00:19 +0100 Subject: [PATCH] StudioWelcome: Allow to download examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If46eb9bc2f24a6c1057fd3db34596c4619ddcb7b Reviewed-by: Henning Gründl Reviewed-by: Alessandro Portale --- src/plugins/studiowelcome/CMakeLists.txt | 1 + src/plugins/studiowelcome/examplecheckout.cpp | 347 ++++++++++++++++++ src/plugins/studiowelcome/examplecheckout.h | 163 ++++++++ .../qml/downloaddialog/ArcItem.qml | 249 +++++++++++++ .../downloaddialog/CircularIndicator.ui.qml | 129 +++++++ .../qml/downloaddialog/CoolProgressBar.ui.qml | 193 ++++++++++ .../qml/downloaddialog/DialogButton.qml | 91 +++++ .../qml/downloaddialog/DialogLabel.qml | 37 ++ .../qml/downloaddialog/MinMaxMapper.qml | 54 +++ .../qml/downloaddialog/RangeMapper.qml | 48 +++ .../downloaddialog/downloaddialog.qmlproject | 47 +++ .../studiowelcome/qml/downloaddialog/main.qml | 312 ++++++++++++++++ .../ExampleCheckout/FileDownloader.qml | 59 +++ .../ExampleCheckout/FileExtractor.qml | 41 +++ .../mockData/ExampleCheckout/qmldir | 2 + .../qml/welcomepage/ExamplesModel.qml | 9 + .../qml/welcomepage/HoverOverDesaturate.qml | 21 ++ .../qml/welcomepage/ProjectsGrid.qml | 1 + .../qml/welcomepage/images/downloadCloud.svg | 29 ++ .../images/highendivi_thumbnail.png | Bin 0 -> 48336 bytes .../studiowelcome/qml/welcomepage/main.qml | 2 +- src/plugins/studiowelcome/studiowelcome.pro | 4 +- src/plugins/studiowelcome/studiowelcome.qbs | 2 + .../studiowelcome/studiowelcomeplugin.cpp | 25 +- 24 files changed, 1862 insertions(+), 4 deletions(-) create mode 100644 src/plugins/studiowelcome/examplecheckout.cpp create mode 100644 src/plugins/studiowelcome/examplecheckout.h create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/main.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir create mode 100644 src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg create mode 100644 src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index b04caf2a6d4..fe7f34ca7f4 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(StudioWelcome DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES studiowelcomeplugin.cpp studiowelcomeplugin.h + examplecheckout.cpp examplecheckout.h studiowelcome_global.h studiowelcome.qrc "${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc" diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp new file mode 100644 index 00000000000..c7180155d85 --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "examplecheckout.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ExampleCheckout::ExampleCheckout(QObject *) {} + +void ExampleCheckout::checkoutExample(const QUrl &url) +{ + FileDownloader::registerQmlType(); + static bool once = []() { + FileDownloader::registerQmlType(); + FileExtractor::registerQmlType(); + return true; + }(); + + QTC_ASSERT(once, ;); + + m_dialog.reset(new QDialog(Core::ICore::dialogParent())); + m_dialog->setModal(true); + m_dialog->setFixedSize(620, 300); + QHBoxLayout *layout = new QHBoxLayout(m_dialog.get()); + layout->setContentsMargins(2, 2, 2, 2); + + auto widget = new QQuickWidget(m_dialog.get()); + + layout->addWidget(widget); + widget->engine()->addImportPath("qrc:/studiofonts"); + + widget->engine()->addImportPath(Core::ICore::resourcePath() + + "/qmldesigner/propertyEditorQmlSources/imports"); + + widget->setSource(QUrl("qrc:/qml/downloaddialog/main.qml")); + + m_dialog->setWindowFlag(Qt::Tool, true); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + rootObject = widget->rootObject(); + + QTC_ASSERT(rootObject, qWarning() << "QML error"; return ); + + rootObject->setProperty("url", url); + + m_dialog->show(); + + rootObject = widget->rootObject(); + + connect(rootObject, SIGNAL(canceled()), this, SLOT(handleCancel())); + connect(rootObject, SIGNAL(accepted()), this, SLOT(handleAccepted())); +} + +QString ExampleCheckout::extractionFolder() const +{ + return m_extrationFolder; +} + +ExampleCheckout::~ExampleCheckout() {} + +void ExampleCheckout::handleCancel() +{ + m_dialog->close(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void ExampleCheckout::handleAccepted() +{ + QQmlProperty property(rootObject, "path"); + m_extrationFolder = property.read().toString(); + m_dialog->close(); + emit finishedSucessfully(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void FileDownloader::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileDownloader"); +} + +FileDownloader::FileDownloader(QObject *parent) + : QObject(parent) +{} + +FileDownloader::~FileDownloader() +{ + m_tempFile.remove(); +} + +void FileDownloader::start() +{ + m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip"); + + m_tempFile.open(QIODevice::WriteOnly); + + auto request = QNetworkRequest(m_url); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true); + QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request); + + QNetworkReply::connect(reply, &QNetworkReply::readyRead, [this, reply]() { + m_tempFile.write(reply->readAll()); + }); + + QNetworkReply::connect(reply, + &QNetworkReply::downloadProgress, + this, + [this](qint64 current, qint64 max) { + if (max == 0) + return; + + m_progress = current * 100 / max; + emit progressChanged(); + }); + + QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() { + if (reply->error()) { + m_tempFile.remove(); + if (m_url != reply->url()) { + m_url = reply->url(); + start(); + } else { + emit downloadFailed(); + } + } else { + m_tempFile.flush(); + m_tempFile.close(); + m_finished = true; + emit finishedChanged(); + } + }); +} + +void FileDownloader::setUrl(const QUrl &url) +{ + m_url = url; + + emit nameChanged(); +} + +QUrl FileDownloader::url() const +{ + return m_url; +} + +bool FileDownloader::finished() const +{ + return m_finished; +} + +bool FileDownloader::error() const +{ + return m_error; +} + +QString FileDownloader::name() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.baseName(); +} + +QString FileDownloader::completeBaseName() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.completeBaseName(); +} + +int FileDownloader::progress() const +{ + return m_progress; +} + +QString FileDownloader::tempFile() const +{ + return QFileInfo(m_tempFile).canonicalFilePath(); +} + +FileExtractor::FileExtractor(QObject *parent) + : QObject(parent) +{ + if (Core::DocumentManager::instance()) + m_targetPath = Core::DocumentManager::projectsDirectory(); + else + m_targetPath = Utils::FilePath::fromString("/temp/"); + + m_timer.setInterval(500); + m_timer.setSingleShot(false); +} + +FileExtractor::~FileExtractor() {} + +void FileExtractor::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileExtractor"); +} + +QString FileExtractor::targetPath() const +{ + return m_targetPath.toUserOutput(); +} + +void FileExtractor::browse() +{ + const QString path = QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + (tr("Choose Directory")), + m_targetPath.toString()); + + if (!path.isEmpty()) + m_targetPath = Utils::FilePath::fromString(path); + + emit targetPathChanged(); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setSourceFile(QString &sourceFilePath) +{ + m_sourceFile = Utils::FilePath::fromString(sourceFilePath); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setArchiveName(QString &filePath) +{ + m_archiveName = filePath; +} + +const QString FileExtractor::detailedText() +{ + return m_detailedText; +} + +bool FileExtractor::finished() const +{ + return m_finished; +} + +QString FileExtractor::currentFile() const +{ + return m_currentFile; +} + +QString FileExtractor::size() const +{ + return m_size; +} + +QString FileExtractor::count() const +{ + return m_count; +} + +bool FileExtractor::targetFolderExists() const +{ + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + return QFileInfo(targetFolder).exists(); +} + +QString FileExtractor::archiveName() const +{ + return m_archiveName; +} + +QString FileExtractor::sourceFile() const +{ + return m_sourceFile.toString(); +} + +void FileExtractor::extract() +{ + Utils::Archive *archive = Utils::Archive::unarchive(m_sourceFile, m_targetPath); + archive->setParent(this); + QTC_ASSERT(archive, return ); + + m_timer.start(); + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable(); + + QTimer::connect(&m_timer, &QTimer::timeout, [this, bytesBefore, targetFolder]() { + static QHash hash; + QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories); + + int count = 0; + while (it.hasNext()) { + if (!hash.contains(it.fileName())) { + m_currentFile = it.fileName(); + hash.insert(m_currentFile, 0); + emit currentFileChanged(); + } + it.next(); + count++; + } + + m_size = QString::number(bytesBefore + - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable()); + + m_count = QString::number(count); + emit sizeChanged(); + }); + + QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) { + m_detailedText += output; + emit detailedTextChanged(); + }); + + QObject::connect(archive, &Utils::Archive::finished, [this](bool ret) { + m_finished = ret; + m_timer.stop(); + emit finishedChanged(); + QTC_ASSERT(ret, ;); + }); +} diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h new file mode 100644 index 00000000000..0038d7f2c0f --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QDialog; +QT_END_NAMESPACE + +class ExampleCheckout : public QObject +{ + Q_OBJECT +public: + explicit ExampleCheckout(QObject *parent = nullptr); + + Q_INVOKABLE void checkoutExample(const QUrl &url); + + QString extractionFolder() const; + + ~ExampleCheckout(); + +public slots: + void handleCancel(); + void handleAccepted(); + +signals: + void finishedSucessfully(); + +private: + std::unique_ptr m_dialog; + QObject *rootObject = nullptr; + QString m_extrationFolder; +}; + +class FileExtractor : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString targetPath READ targetPath NOTIFY targetPathChanged) + Q_PROPERTY(QString archiveName READ archiveName WRITE setArchiveName) + Q_PROPERTY(QString detailedText READ detailedText NOTIFY detailedTextChanged) + Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged) + Q_PROPERTY(QString size READ size NOTIFY sizeChanged) + Q_PROPERTY(QString count READ count NOTIFY sizeChanged) + Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged) + +public: + explicit FileExtractor(QObject *parent = nullptr); + ~FileExtractor(); + + static void registerQmlType(); + + QString targetPath() const; + void setSourceFile(QString &sourceFilePath); + void setArchiveName(QString &filePath); + const QString detailedText(); + bool finished() const; + QString currentFile() const; + QString size() const; + QString count() const; + bool targetFolderExists() const; + + QString sourceFile() const; + QString archiveName() const; + + Q_INVOKABLE void browse(); + Q_INVOKABLE void extract(); + +signals: + void targetPathChanged(); + void detailedTextChanged(); + void finishedChanged(); + void currentFileChanged(); + void sizeChanged(); + void targetFolderExistsChanged(); + +private: + Utils::FilePath m_targetPath; + Utils::FilePath m_sourceFile; + QString m_detailedText; + bool m_finished = false; + QTimer m_timer; + QString m_currentFile; + QString m_size; + QString m_count; + QString m_archiveName; +}; + +class FileDownloader : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QUrl url READ url WRITE setUrl) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool error READ error NOTIFY errorChanged) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QString tempFile READ tempFile NOTIFY finishedChanged) + +public: + explicit FileDownloader(QObject *parent = nullptr); + + ~FileDownloader(); + + void setUrl(const QUrl &url); + QUrl url() const; + bool finished() const; + bool error() const; + static void registerQmlType(); + QString name() const; + QString completeBaseName() const; + int progress() const; + QString tempFile() const; + + Q_INVOKABLE void start(); + +signals: + void finishedChanged(); + void errorChanged(); + void nameChanged(); + void progressChanged(); + void downloadFailed(); + +private: + QUrl m_url; + bool m_finished = false; + bool m_error = false; + int m_progress = 0; + QFile m_tempFile; +}; diff --git a/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml new file mode 100644 index 00000000000..fa38d302dba --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Shapes 1.0 + +Shape { + id: root + + implicitWidth: 100 + implicitHeight: 100 + + property alias gradient: path.fillGradient + property alias strokeStyle: path.strokeStyle + property alias strokeWidth: path.strokeWidth + property alias strokeColor: path.strokeColor + property alias dashPattern: path.dashPattern + property alias joinStyle: path.joinStyle + property alias fillColor: path.fillColor + property alias capStyle: path.capStyle + property alias dashOffset: path.dashOffset + + property real begin: 0 + property real end: 90 + + property real arcWidth: 10 + + property real arcWidthBegin: arcWidth + property real arcWidthEnd: arcWidth + + property real radiusInnerAdjust: 0 + property real radiusOuterAdjust: 0 + + property real alpha: clamp(sortedEnd() - sortedBegin(),0, 359.9) + + layer.enabled: antialiasing + layer.smooth: antialiasing + layer.textureSize: Qt.size(width * 2, height * 2) + property bool outlineArc: false + + property bool round: false + + property bool roundEnd: round + property bool roundBegin: round + + function clamp(num, min, max) { + return num <= min ? min : num >= max ? max : num; + } + + function myCos(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.cos(angleInRadians) + } + + function mySin(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.sin(angleInRadians) + } + + function polarToCartesianX(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var x = centerX + radius * Math.cos(angleInRadians) + return x + } + + function polarToCartesianY(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var y = centerY + radius * Math.sin(angleInRadians); + return y + } + + function calc() + { + path.__xRadius = root.width / 2 - root.strokeWidth / 2 + path.__yRadius = root.height / 2 - root.strokeWidth / 2 + + path.__Xcenter = root.width / 2 + path.__Ycenter = root.height / 2 + + path.startX = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedBegin() - 90) + root.__beginOff * myCos(root.sortedBegin() + 90) + path.startY = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedBegin() - 90) + root.__beginOff * mySin(root.sortedBegin() + 90) + + arc1.x = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedEnd() - 90) + root.__endOff * myCos(root.sortedEnd() + 90) + arc1.y = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedEnd() - 90) + root.__endOff * mySin(root.sortedEnd() + 90) + + arc1.radiusX = path.__xRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + arc1.radiusY = path.__yRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + + arc1.useLargeArc = root.alpha > 180 + } + + function sortedBegin() + { + return(Math.min(root.begin, root.end)) + } + + function sortedEnd() + { + return(Math.max(root.begin, root.end)) + } + + + onWidthChanged: calc() + onHeightChanged: calc() + onBeginChanged: calc() + onEndChanged: calc() + onAlphaChanged: calc() + + ShapePath { + id: path + + property real __xRadius + property real __yRadius + + property real __Xcenter + property real __Ycenter + + strokeColor: "red" + strokeWidth: 4 + capStyle: ShapePath.FlatCap + } + + property real __beginOff: { + + if (root.arcWidthEnd > root.arcWidthBegin) + return (root.arcWidthEnd - root.arcWidthBegin) / 2 + + return 0; + } + + property real __endOff: { + + if (root.arcWidthBegin > root.arcWidthEnd) + return (root.arcWidthBegin - root.arcWidthEnd) / 2 + + return 0; + } + + property real __startP: root.arcWidthBegin + __beginOff + property real __endP: root.arcWidthEnd + __endOff + + Item { + id: shapes + PathArc { + id: arc1 + property bool add: true + } + + PathLine { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: !root.roundEnd && (root.outlineArc && root.alpha < 359.8) + + } + + PathArc { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundEnd && (root.outlineArc && root.alpha < 359.8) + } + + PathMove { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: root.outlineArc && root.alpha > 359.7 + } + + PathArc { + id: arc2 + useLargeArc: arc1.useLargeArc + + radiusX: path.__xRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + radiusY:path.__yRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + + x: path.startX + root.arcWidthBegin * myCos(root.sortedBegin()) + y: path.startY + root.arcWidthBegin * mySin(root.sortedBegin()) + + direction: PathArc.Counterclockwise + + property bool add: root.outlineArc + } + + + PathLine { + x: path.startX + y: path.startY + property bool add: !root.roundBegin && root.outlineArc && root.alpha < 359.8 + + } + + PathArc { + x: path.startX + y: path.startY + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundBegin && root.outlineArc && root.alpha < 359.8 + } + + PathMove { + x: path.startX + y: path.startY + property bool add: root.outlineArc && root.alpha == 360 + } + } + + function invalidatePaths() { + if (!root.__completed) + return + + for (var i = 0; i < shapes.resources.length; i++) { + var s = shapes.resources[i]; + if (s.add) + path.pathElements.push(s) + } + + } + + property bool __completed: false + + Component.onCompleted: { + root.__completed = true + invalidatePaths() + calc() + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml new file mode 100644 index 00000000000..15b2e265527 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Rectangle { + id: rectangle + width: 60 + height: 60 + color: "#8c8c8c" + radius: 50 + property alias inputMax: rangeMapper.inputMax + property alias inputMin: rangeMapper.inputMin + property alias value: minMaxMapper.input + + ArcItem { + id: arc + x: -1 + y: -1 + width: 62 + height: 62 + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + end: rangeMapper.value + antialiasing: true + strokeWidth: 8 + strokeColor: "#ffffff" + capStyle: 32 + fillColor: "#00000000" + } + + RangeMapper { + id: rangeMapper + outputMax: 358 + input: minMaxMapper.value + } + + MinMaxMapper { + id: minMaxMapper + input: 95 + max: rangeMapper.inputMax + min: rangeMapper.inputMin + } + + Rectangle { + id: rectangle1 + width: 60 + height: 60 + color: "#ffffff" + radius: 40 + anchors.verticalCenter: parent.verticalCenter + scale: 1 + anchors.horizontalCenter: parent.horizontalCenter + } + + Timeline { + id: timeline + currentFrame: rangeMapper.value + enabled: true + endFrame: 360 + startFrame: 0 + + KeyframeGroup { + target: rectangle1 + property: "opacity" + Keyframe { + frame: 0 + value: 0 + } + + Keyframe { + frame: 360 + value: 1 + } + } + + KeyframeGroup { + target: rectangle1 + property: "scale" + Keyframe { + frame: 360 + value: 1 + } + + Keyframe { + frame: 0 + value: 0.1 + } + } + + KeyframeGroup { + target: arc + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 40 + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml new file mode 100644 index 00000000000..b48880406c5 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Item { + id: coolProgressBar + width: 605 + height: 16 + property alias value: timeline.currentFrame + clip: true + + Timeline { + id: timeline + enabled: true + endFrame: 100 + startFrame: 0 + + KeyframeGroup { + target: rectangle + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 150 + frame: 25 + } + + Keyframe { + value: 300 + frame: 50 + } + + Keyframe { + value: 450 + frame: 75 + } + + Keyframe { + value: 600 + frame: 100 + } + } + + KeyframeGroup { + target: rectangle1 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 300 + frame: 25 + } + + Keyframe { + value: 450 + frame: 50 + } + + Keyframe { + value: 600 + frame: 75 + } + } + + KeyframeGroup { + target: rectangle2 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 450 + frame: 25 + } + + Keyframe { + value: 600 + frame: 50 + } + } + + KeyframeGroup { + target: rectangle3 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 600 + frame: 25 + } + } + + KeyframeGroup { + target: content + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 50 + } + } + } + + Item { + id: content + anchors.fill: parent + + Rectangle { + id: rectangle + y: 0 + width: 80 + height: 16 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle1 + y: 0 + width: 80 + height: 16 + opacity: 0.6 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle2 + y: 0 + width: 80 + height: 16 + opacity: 0.4 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle3 + y: 0 + width: 80 + height: 16 + opacity: 0.2 + color: "#ffffff" + radius: 12 + } + } +} + +/*##^## +Designer { + D{i:0;height:16;width:590}D{i:1} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml new file mode 100644 index 00000000000..d21acdde359 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Templates 2.1 as T + +T.Button { + id: control + + implicitWidth: Math.max(buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 4 + rightPadding: 4 + + text: "My Button" + + property color defaultColor: "#b9b9ba" + property color checkedColor: "#ffffff" + + background: buttonBackground + Rectangle { + id: buttonBackground + color: control.defaultColor + implicitWidth: 100 + implicitHeight: 40 + opacity: enabled ? 1 : 0.3 + radius: 0 + border.width: 1 + } + + contentItem: textItem + Text { + id: textItem + text: control.text + + opacity: enabled ? 1.0 : 0.3 + color: "#bababa" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + states: [ + State { + name: "normal" + when: !control.down && !control.checked + PropertyChanges { + target: buttonBackground + color: "#2d2e30" + } + }, + State { + name: "down" + when: control.down || control.checked + PropertyChanges { + target: textItem + color: control.checkedColor + } + + PropertyChanges { + target: buttonBackground + color: "#545456" + border.color: "#70a2f5" + border.width: 2 + } + } + ] +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml new file mode 100644 index 00000000000..c5dac79a504 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Text { + font.family: StudioFonts.titilliumWeb_light + color: root.textColor +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml new file mode 100644 index 00000000000..451c098f9e3 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property bool minClipped: object.input < object.min + property bool maxClipped: object.input > object.max + property bool outOfRage: object.maxClipped ||object.minClipped + + property real value: { + if (object.maxClipped) + return object.max + + if (object.minClipped) + return object.min + + return object.input + } + + property real min: 0 + property real max: 100 +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml new file mode 100644 index 00000000000..dc75325b084 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property real value: { + var slope = (object.outputMax - object.outputMin) / (object.inputMax - object.inputMin) + return object.outputMin + slope * (object.input - object.inputMin) + } + + property real inputMin: 0 + property real inputMax: 100 + property real outputMin: 0 + property real outputMax: 100 + +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject new file mode 100644 index 00000000000..880c6022a96 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +import QmlProject 1.1 + +Project { + mainFile: "main.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + importPaths: [ "mockData", "../../../../share/3rdparty/studiofonts", "../../../../../share/qtcreator/qmldesigner/propertyEditorQmlSources/imports" ] + + Environment { + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/main.qml b/src/plugins/studiowelcome/qml/downloaddialog/main.qml new file mode 100644 index 00000000000..cb7f62a68c4 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/main.qml @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Rectangle { + id: root + property alias url: downloader.url + property string path: fileExtractor.targetPath + width: 620 + height: 300 + + color: "#2d2e30" + + property color textColor: "#b9b9ba" + + signal canceled + signal accepted + + StackLayout { + id: stackLayout + anchors.fill: parent + currentIndex: 0 + + FileExtractor { + id: fileExtractor + sourceFile: downloader.tempFile + archiveName: downloader.completeBaseName + } + + FileDownloader { + id: downloader + //onNameChanged: start() + onFinishedChanged: { + button.enabled = downloader.finished + if (!downloader.finished) + stackLayout.currentIndex = 3 + } + + onDownloadFailed: stackLayout.currentIndex = 3 + } + + Item { + id: download + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: button + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: false + onClicked: stackLayout.currentIndex = 1 + } + + CoolProgressBar { + id: coolProgressBar + width: 605 + anchors.top: parent.top + value: downloader.progress + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 69 + } + + DialogLabel { + x: 201 + text: "Downloading Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + DialogButton { + id: downloadbutton + y: 420 + enabled: !button.enabled + text: qsTr("Start Download") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + onClicked: { + downloadbutton.enabled = false + downloader.start() + } + } + + CircularIndicator { + id: circularIndicator + x: 304 + anchors.top: parent.top + anchors.horizontalCenterOffset: 0 + value: downloader.progress + anchors.topMargin: 120 + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + Item { + id: destiationfolder + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: nextPageDestination + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + enabled: !fileExtractor.targetFolderExists + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: { + stackLayout.currentIndex = 2 + fileExtractor.extract() + } + } + + RowLayout { + y: 114 + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: 104 + anchors.leftMargin: 67 + + TextField { + id: textField + text: fileExtractor.targetPath + Layout.fillWidth: true + font.family: StudioFonts.titilliumWeb_light + wrapMode: Text.WordWrap + selectByMouse: true + readOnly: true + } + + DialogButton { + id: browse + text: qsTr("Browse") + onClicked: fileExtractor.browse() + } + } + + DialogLabel { + id: label + y: 436 + text: qsTr("Folder ") + downloader.completeBaseName + (" already exists") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + visible: !nextPageDestination.enabled + } + + DialogButton { + id: button5 + x: 400 + y: 420 + text: qsTr("Cancel") + anchors.right: nextPageDestination.left + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + text: "Choose installation folder" + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + x: 8 + } + } + + Item { + id: extraction + Layout.fillHeight: true + Layout.fillWidth: true + + + DialogButton { + id: done + x: 532 + y: 432 + text: qsTr("Open") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: fileExtractor.finished + onClicked: root.accepted() + } + + + DialogLabel { + id: text2 + text: fileExtractor.count + " files " + (fileExtractor.size / 1024 / 1024).toFixed(2) + " MB "+ fileExtractor.currentFile + anchors.left: parent.left + anchors.bottom: parent.bottom + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + } + + + DialogButton { + id: details + x: 8 + text: qsTr("Details") + anchors.top: parent.top + anchors.topMargin: 66 + anchors.horizontalCenter: parent.horizontalCenter + checkable: true + } + + + DialogLabel { + x: 8 + text: "Extracting Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + Flickable { + visible: details.checked + clip: true + anchors.bottomMargin: 60 + anchors.rightMargin: 20 + anchors.leftMargin: 20 + anchors.topMargin: 120 + anchors.fill: parent + id: flickable + interactive: false + + DialogLabel { + onHeightChanged: flickable.contentY = text1.implicitHeight - flickable.height + id: text1 + + text: fileExtractor.detailedText + + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + + width: flickable.width + } + } + } + + Item { + id: failed + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: finish + x: 532 + y: 432 + text: qsTr("Finish") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + x: 8 + text: qsTr("Download failed") + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml new file mode 100644 index 00000000000..bf873ec5631 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + id: root + + signal downloadFailed + + property bool finished: false + + property bool url + + property int progress: 55 + Behavior on progress { PropertyAnimation { + duration: 2000 + } + } + + function start() { + timer.start() + root.progress = 100 + + } + + property Timer timer: Timer { + interval: 2000 + repeat: false + onTriggered: { + root.finished + root.progress = 1000 + finished = true + } + + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml new file mode 100644 index 00000000000..d3ee8e20f6b --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + signal finished + + property string sourceFile: "SomeExample.zip" + property string archiveName: "SomeExample" + + property string targetPath: "/extract/here" + + property string detailedText: "Start" + + "\n1 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n2 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n3 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\nend" +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir new file mode 100644 index 00000000000..7c2bb0bcd49 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir @@ -0,0 +1,2 @@ +FileDownloader 1.0 FileDownloader.qml +FileExtractor 1.0 FileExtractor.qml diff --git a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml index 5e9fe07985c..3f33f0205e8 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml @@ -74,4 +74,13 @@ ListModel { thumbnail: "images/washingmachinedemo_thumbnail.png" displayName: "Washing Machine" } + + ListElement { + projectName: "highendivisystem" + qmlFileName: "Screen01.ui.qml" + thumbnail: "images/highendivi_thumbnail.png" + displayName: "Highend IVI System" + url: "https://download.qt.io/learning/examples/qtdesignstudio/highendivisystem.zip" + showDownload: true + } } diff --git a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml index e160a1f70e3..a7d7501a52c 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml @@ -35,6 +35,8 @@ Item { property alias imageSource: image.source property alias labelText: label.text + property alias downloadIcon: downloadCloud.visible + onVisibleChanged: { animateOpacity.start() animateScale.start() @@ -89,6 +91,19 @@ Item { rectangle.color = "#262728" label.color = "#686868" } + + Image { + id: downloadCloud + x: 210 + y: 118 + width: 60 + height: 60 + source: "images/downloadCloud.svg" + sourceSize.height: 60 + sourceSize.width: 60 + fillMode: Image.PreserveAspectFit + visible: false + } } } @@ -187,3 +202,9 @@ Item { font.family: StudioFonts.titilliumWeb_regular } } + +/*##^## +Designer { + D{i:0;formeditorZoom:1.3300000429153442}D{i:8} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml index 6faf3a65547..6a18d10ded3 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml @@ -39,6 +39,7 @@ GridView { id: hoverOverDesaturate imageSource: typeof(thumbnail) === "undefined" ? "images/thumbnail_test.png" : thumbnail; labelText: displayName + downloadIcon: typeof(showDownload) === "undefined" ? false : showDownload; SequentialAnimation { id: animation diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg new file mode 100644 index 00000000000..3a527c3e54f --- /dev/null +++ b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg @@ -0,0 +1,29 @@ + + + + + + + diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png b/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..5428c80776ec89562e2bfdb21f7e209ddfbf7ac9 GIT binary patch literal 48336 zcmeAS@N?(olHy`uVBq!ia0y~yVEDzrz_5dZje&vTRL#dI1_lPUByV>YhW{YAVDIwD z3=9mM1s;*b3=G`DAk4@xYmNj10|R@Br>`sfQzj{XJ&WfFMy(7C3Jjhujv*Dd?(B`6 z9DB1=?c3VgW!CrSG`OgxE#NYpG{qxWH(SZHWP7x3@RFSJ-v|fWm?{odpv~S<%yY=Qu4{j^`vJ(6&*dWU!$f3ZXz_hZy;mY=a`-~|y&R3PE^>6%l z?N9Q$f5-nl`qa6jii7dNC+TbYYwFW%oBzoghwo2$9De%!739W&HA2$usw>|1M3u!~ELx^y{d7xk{h?-(FXET)FexlQX^N zx%BLLZ(na`+!og=`(JatZn*#1ukF+KEB_Tsu$Md2yFYTDypf#qx8p|Z`Hg3+sA4ku zw|&?0XP-^i?fkoQ#nX*EdGkC!@02|Kx$SBC68%Fb{=eA$|2M~h?Tj^ZIqF$1@MXRZ zO>dH7U-ReZr{7N%H}cM(c7L~>;MF&d_Y;&>$?9Cuo0NFq%(vuI(peH#*W

|QR@ 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 I&MBb@04#3?!T #include @@ -175,9 +176,29 @@ public: QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/index.html")); } - Q_INVOKABLE void openExample(const QString &example, const QString &formFile) + Q_INVOKABLE void openExample(const QString &example, const QString &formFile, const QString &url) { - const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + example + ".qmlproject"; + if (!url.isEmpty()) { + ExampleCheckout *checkout = new ExampleCheckout; + checkout->checkoutExample(QUrl::fromUserInput(url)); + connect(checkout, + &ExampleCheckout::finishedSucessfully, + this, + [checkout, this, formFile, example]() { + const QString projectFile = checkout->extractionFolder() + "/" + example + + "/" + example + ".qmlproject"; + + ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); + const QString qmlFile = checkout->extractionFolder() + "/" + example + "/" + + formFile; + + Core::EditorManager::openEditor(qmlFile); + }); + return; + } + + const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + + example + ".qmlproject"; ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + formFile; Core::EditorManager::openEditor(qmlFile);