QmlDesigner: Add functionality to welcome plugin

* Add extraction progress and birth time
* Add URL probing in downloader
* Add last modified and available information
* Overload openExample() function

Task-number: QDS-6174
Change-Id: I68782629da3ec4da5aab95d00510b7bc7085aa66
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Henning Gruendl
2022-02-11 10:29:13 +01:00
committed by Henning Gründl
parent fba9a3514f
commit c2cd524cdb
3 changed files with 140 additions and 19 deletions

View File

@@ -41,6 +41,8 @@
#include <QQuickItem> #include <QQuickItem>
#include <QQuickWidget> #include <QQuickWidget>
#include <algorithm>
using namespace Utils; using namespace Utils;
ExampleCheckout::ExampleCheckout(QObject *) {} ExampleCheckout::ExampleCheckout(QObject *) {}
@@ -137,11 +139,11 @@ FileDownloader::~FileDownloader()
void FileDownloader::start() void FileDownloader::start()
{ {
m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip"); m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip");
m_tempFile.open(QIODevice::WriteOnly); m_tempFile.open(QIODevice::WriteOnly);
auto request = QNetworkRequest(m_url); auto request = QNetworkRequest(m_url);
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true); request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::UserVerifiedRedirectPolicy);
QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request); QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request);
QNetworkReply::connect(reply, &QNetworkReply::readyRead, [this, reply]() { QNetworkReply::connect(reply, &QNetworkReply::readyRead, [this, reply]() {
@@ -159,20 +161,20 @@ void FileDownloader::start()
emit progressChanged(); emit progressChanged();
}); });
QNetworkReply::connect(reply, &QNetworkReply::redirected, [reply](const QUrl &url) {
emit reply->redirectAllowed();
});
QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() { QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() {
if (reply->error()) { if (reply->error()) {
m_tempFile.remove(); m_tempFile.remove();
if (m_url != reply->url()) {
m_url = reply->url();
start();
} else {
qDebug() << Q_FUNC_INFO << m_url << reply->errorString(); qDebug() << Q_FUNC_INFO << m_url << reply->errorString();
emit downloadFailed(); emit downloadFailed();
}
} else { } else {
m_tempFile.flush(); m_tempFile.flush();
m_tempFile.close(); m_tempFile.close();
m_finished = true; m_finished = true;
emit tempFileChanged();
emit finishedChanged(); emit finishedChanged();
} }
}); });
@@ -181,8 +183,9 @@ void FileDownloader::start()
void FileDownloader::setUrl(const QUrl &url) void FileDownloader::setUrl(const QUrl &url)
{ {
m_url = url; m_url = url;
emit nameChanged(); emit nameChanged();
probeUrl();
} }
QUrl FileDownloader::url() const QUrl FileDownloader::url() const
@@ -222,16 +225,71 @@ QString FileDownloader::tempFile() const
return QFileInfo(m_tempFile).canonicalFilePath(); return QFileInfo(m_tempFile).canonicalFilePath();
} }
QDateTime FileDownloader::lastModified() const
{
return m_lastModified;
}
bool FileDownloader::available() const
{
return m_available;
}
void FileDownloader::probeUrl()
{
auto request = QNetworkRequest(m_url);
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::UserVerifiedRedirectPolicy);
QNetworkReply *reply = Utils::NetworkAccessManager::instance()->head(request);
QNetworkReply::connect(reply, &QNetworkReply::redirected, [reply](const QUrl &url) {
emit reply->redirectAllowed();
});
QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() {
if (reply->error())
return;
m_lastModified = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
emit lastModifiedChanged();
m_available = true;
emit availableChanged();
});
QNetworkReply::connect(reply,
&QNetworkReply::errorOccurred,
[this, reply](QNetworkReply::NetworkError code) {
// QNetworkReply::HostNotFoundError
// QNetworkReply::ContentNotFoundError
m_available = false;
emit availableChanged();
});
}
FileExtractor::FileExtractor(QObject *parent) FileExtractor::FileExtractor(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
if (Core::DocumentManager::instance()) m_targetPath = Utils::FilePath::fromString(
m_targetPath = Core::DocumentManager::projectsDirectory(); QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
if (!m_targetPath.isEmpty())
m_targetPath = m_targetPath.pathAppended("QtDesignStudio");
else else
m_targetPath = "/temp/"; m_targetPath = "/temp/";
m_timer.setInterval(500); m_timer.setInterval(100);
m_timer.setSingleShot(false); m_timer.setSingleShot(false);
QObject::connect(this, &FileExtractor::targetFolderExistsChanged, [this]() {
if (targetFolderExists()) {
m_birthTime = QFileInfo(m_targetPath.toString() + "/" + m_archiveName).birthTime();
} else
m_birthTime = QDateTime();
emit birthTimeChanged();
});
} }
FileExtractor::~FileExtractor() {} FileExtractor::~FileExtractor() {}
@@ -297,8 +355,17 @@ QString FileExtractor::count() const
bool FileExtractor::targetFolderExists() const bool FileExtractor::targetFolderExists() const
{ {
const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; return QFileInfo::exists(m_targetPath.toString() + "/" + m_archiveName);
return QFileInfo(targetFolder).exists(); }
int FileExtractor::progress() const
{
return m_progress;
}
QDateTime FileExtractor::birthTime() const
{
return m_birthTime;
} }
QString FileExtractor::archiveName() const QString FileExtractor::archiveName() const
@@ -320,8 +387,9 @@ void FileExtractor::extract()
m_timer.start(); m_timer.start();
const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName;
qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable(); qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
qint64 compressedSize = QFileInfo(m_sourceFile.toString()).size();
QTimer::connect(&m_timer, &QTimer::timeout, [this, bytesBefore, targetFolder]() { QTimer::connect(&m_timer, &QTimer::timeout, [this, bytesBefore, targetFolder, compressedSize]() {
static QHash<QString, int> hash; static QHash<QString, int> hash;
QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories); QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories);
@@ -336,9 +404,15 @@ void FileExtractor::extract()
count++; count++;
} }
m_size = QString::number(bytesBefore qint64 currentSize = bytesBefore
- QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable()); - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
// We can not get the uncompressed size of the archive yet, that is why we use an
// approximation. We assume a 50% compression rate.
m_progress = std::min(100ll, currentSize * 100 / compressedSize * 2);
emit progressChanged();
m_size = QString::number(currentSize);
m_count = QString::number(count); m_count = QString::number(count);
emit sizeChanged(); emit sizeChanged();
}); });
@@ -351,6 +425,11 @@ void FileExtractor::extract()
QObject::connect(archive, &Utils::Archive::finished, [this](bool ret) { QObject::connect(archive, &Utils::Archive::finished, [this](bool ret) {
m_finished = ret; m_finished = ret;
m_timer.stop(); m_timer.stop();
m_progress = 100;
emit progressChanged();
emit targetFolderExistsChanged();
emit finishedChanged(); emit finishedChanged();
QTC_ASSERT(ret, ;); QTC_ASSERT(ret, ;);
}); });

View File

@@ -78,6 +78,8 @@ class FileExtractor : public QObject
Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile) Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile)
Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged) Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged)
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QDateTime birthTime READ birthTime NOTIFY birthTimeChanged)
public: public:
explicit FileExtractor(QObject *parent = nullptr); explicit FileExtractor(QObject *parent = nullptr);
@@ -94,6 +96,8 @@ public:
QString size() const; QString size() const;
QString count() const; QString count() const;
bool targetFolderExists() const; bool targetFolderExists() const;
int progress() const;
QDateTime birthTime() const;
QString sourceFile() const; QString sourceFile() const;
QString archiveName() const; QString archiveName() const;
@@ -108,6 +112,8 @@ signals:
void currentFileChanged(); void currentFileChanged();
void sizeChanged(); void sizeChanged();
void targetFolderExistsChanged(); void targetFolderExistsChanged();
void progressChanged();
void birthTimeChanged();
private: private:
Utils::FilePath m_targetPath; Utils::FilePath m_targetPath;
@@ -119,6 +125,8 @@ private:
QString m_size; QString m_size;
QString m_count; QString m_count;
QString m_archiveName; QString m_archiveName;
int m_progress = 0;
QDateTime m_birthTime;
}; };
class FileDownloader : public QObject class FileDownloader : public QObject
@@ -131,7 +139,9 @@ class FileDownloader : public QObject
Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged) Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged)
Q_PROPERTY(int progress READ progress NOTIFY progressChanged) Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString tempFile READ tempFile NOTIFY finishedChanged) Q_PROPERTY(QString tempFile READ tempFile NOTIFY tempFileChanged)
Q_PROPERTY(QDateTime lastModified READ lastModified NOTIFY lastModifiedChanged)
Q_PROPERTY(bool available READ available NOTIFY availableChanged)
public: public:
explicit FileDownloader(QObject *parent = nullptr); explicit FileDownloader(QObject *parent = nullptr);
@@ -147,6 +157,8 @@ public:
QString completeBaseName() const; QString completeBaseName() const;
int progress() const; int progress() const;
QString tempFile() const; QString tempFile() const;
QDateTime lastModified() const;
bool available() const;
Q_INVOKABLE void start(); Q_INVOKABLE void start();
@@ -155,12 +167,19 @@ signals:
void errorChanged(); void errorChanged();
void nameChanged(); void nameChanged();
void progressChanged(); void progressChanged();
void tempFileChanged();
void downloadFailed(); void downloadFailed();
void lastModifiedChanged();
void availableChanged();
private: private:
void probeUrl();
QUrl m_url; QUrl m_url;
bool m_finished = false; bool m_finished = false;
bool m_error = false; bool m_error = false;
int m_progress = 0; int m_progress = 0;
QFile m_tempFile; QFile m_tempFile;
QDateTime m_lastModified;
bool m_available;
}; };

View File

@@ -232,6 +232,28 @@ public:
QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/index.html")); QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/index.html"));
} }
Q_INVOKABLE void openExample(const QString &examplePath,
const QString &exampleName,
const QString &formFile,
const QString &explicitQmlproject)
{
const QString exampleFolder = examplePath + "/" + exampleName + "/";
QString projectFile = exampleFolder + exampleName + ".qmlproject";
if (!explicitQmlproject.isEmpty())
projectFile = exampleFolder + explicitQmlproject;
ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile);
const QString qmlFile = QFileInfo(projectFile).dir().absolutePath() + "/" + formFile;
// This timer should be replaced with a signal send from project loading
QTimer::singleShot(1000, [qmlFile](){
Core::EditorManager::openEditor(Utils::FilePath::fromString(qmlFile));
});
}
Q_INVOKABLE void openExample(const QString &example, Q_INVOKABLE void openExample(const QString &example,
const QString &formFile, const QString &formFile,
const QString &url, const QString &url,
@@ -272,6 +294,7 @@ public:
Core::EditorManager::openEditor(qmlFile); Core::EditorManager::openEditor(qmlFile);
} }
public slots: public slots:
void resetProjects(); void resetProjects();