mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-04 05:04:33 +00:00
Qt: Use QtAsyncTaskWithProgress for cover downloader
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
|
||||
#include "coverdownloadwindow.h"
|
||||
#include "qthost.h"
|
||||
#include "qtprogresscallback.h"
|
||||
|
||||
#include "core/game_list.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
|
||||
#include "moc_coverdownloadwindow.cpp"
|
||||
|
||||
@@ -17,152 +18,77 @@ CoverDownloadWindow::CoverDownloadWindow() : QWidget()
|
||||
updateEnabled();
|
||||
|
||||
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadWindow::onStartClicked);
|
||||
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadWindow::onCloseClicked);
|
||||
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadWindow::close);
|
||||
connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadWindow::updateEnabled);
|
||||
}
|
||||
|
||||
CoverDownloadWindow::~CoverDownloadWindow()
|
||||
{
|
||||
Assert(!m_thread);
|
||||
}
|
||||
CoverDownloadWindow::~CoverDownloadWindow() = default;
|
||||
|
||||
void CoverDownloadWindow::closeEvent(QCloseEvent* ev)
|
||||
{
|
||||
QtUtils::SaveWindowGeometry(this);
|
||||
QWidget::closeEvent(ev);
|
||||
cancelThread();
|
||||
if (m_task)
|
||||
m_task->cancel();
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::onDownloadStatus(const QString& text)
|
||||
{
|
||||
m_ui.status->setText(text);
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::onDownloadProgress(int value, int range)
|
||||
{
|
||||
// Limit to once every five seconds, otherwise it's way too flickery.
|
||||
// Ideally in the future we'd have some way to invalidate only a single cover.
|
||||
if (m_last_refresh_time.GetTimeSeconds() >= 5.0f)
|
||||
{
|
||||
emit coverRefreshRequested();
|
||||
m_last_refresh_time.Reset();
|
||||
}
|
||||
|
||||
if (range != m_ui.progress->maximum())
|
||||
m_ui.progress->setMaximum(range);
|
||||
m_ui.progress->setValue(value);
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::onDownloadComplete()
|
||||
{
|
||||
emit coverRefreshRequested();
|
||||
|
||||
m_ui.status->setText(tr("Download complete."));
|
||||
|
||||
QString error;
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->wait();
|
||||
if (!m_thread->getResult())
|
||||
{
|
||||
if (const std::string& err_str = m_thread->getError().GetDescription(); !err_str.empty())
|
||||
m_ui.status->setText(QString::fromStdString(err_str));
|
||||
}
|
||||
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::onStartClicked()
|
||||
{
|
||||
if (m_thread)
|
||||
cancelThread();
|
||||
else
|
||||
startThread();
|
||||
if (m_task)
|
||||
{
|
||||
m_task->cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> urls;
|
||||
const bool use_serials = m_ui.useSerialFileNames->isChecked();
|
||||
for (const QString& str : m_ui.urls->toPlainText().split(QChar('\n')))
|
||||
urls.push_back(str.toStdString());
|
||||
|
||||
m_task = QtAsyncTaskWithProgress::create(
|
||||
this, [this, urls = std::move(urls), use_serials](ProgressCallback* const progress) {
|
||||
Error error;
|
||||
const bool result = GameList::DownloadCovers(urls, use_serials, progress, &error);
|
||||
return [this, result, error = std::move(error)]() { downloadComplete(result, error); };
|
||||
});
|
||||
|
||||
m_task->connectWidgets(m_ui.status, m_ui.progress, m_ui.start);
|
||||
|
||||
connect(m_task, &QtAsyncTaskWithProgress::progressValueUpdated, this, [this]() {
|
||||
// Limit to once every five seconds, otherwise it's way too flickery.
|
||||
// Ideally in the future we'd have some way to invalidate only a single cover.
|
||||
if (m_last_refresh_time.GetTimeSeconds() >= 5.0f)
|
||||
{
|
||||
emit coverRefreshRequested();
|
||||
m_last_refresh_time.Reset();
|
||||
}
|
||||
});
|
||||
|
||||
m_task->start();
|
||||
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::onCloseClicked()
|
||||
void CoverDownloadWindow::downloadComplete(bool result, const Error& error)
|
||||
{
|
||||
if (m_thread)
|
||||
cancelThread();
|
||||
emit coverRefreshRequested();
|
||||
m_ui.status->setText(tr("Download complete."));
|
||||
if (!result)
|
||||
{
|
||||
if (const std::string& err_str = error.GetDescription(); !err_str.empty())
|
||||
m_ui.status->setText(QString::fromStdString(err_str));
|
||||
}
|
||||
|
||||
close();
|
||||
m_task = nullptr;
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::updateEnabled()
|
||||
{
|
||||
const bool running = static_cast<bool>(m_thread);
|
||||
const bool running = static_cast<bool>(m_task);
|
||||
m_ui.start->setText(running ? tr("Stop") : tr("Start"));
|
||||
m_ui.start->setEnabled(running || !m_ui.urls->toPlainText().isEmpty());
|
||||
m_ui.close->setEnabled(!running);
|
||||
m_ui.urls->setEnabled(!running);
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::startThread()
|
||||
{
|
||||
m_thread = new CoverDownloadThread(m_ui.urls->toPlainText(), m_ui.useSerialFileNames->isChecked());
|
||||
m_last_refresh_time.Reset();
|
||||
m_thread->moveToThread(m_thread);
|
||||
connect(m_thread, &CoverDownloadThread::statusUpdated, this, &CoverDownloadWindow::onDownloadStatus);
|
||||
connect(m_thread, &CoverDownloadThread::progressUpdated, this, &CoverDownloadWindow::onDownloadProgress);
|
||||
connect(m_thread, &CoverDownloadThread::threadFinished, this, &CoverDownloadWindow::onDownloadComplete);
|
||||
m_thread->start();
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void CoverDownloadWindow::cancelThread()
|
||||
{
|
||||
if (!m_thread)
|
||||
return;
|
||||
|
||||
m_thread->requestInterruption();
|
||||
m_thread->wait();
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
CoverDownloadThread::CoverDownloadThread(const QString& urls, bool use_serials) : QThread(), m_use_serials(use_serials)
|
||||
{
|
||||
for (const QString& str : urls.split(QChar('\n')))
|
||||
m_urls.push_back(str.toStdString());
|
||||
}
|
||||
|
||||
CoverDownloadThread::~CoverDownloadThread() = default;
|
||||
|
||||
bool CoverDownloadThread::IsCancelled() const
|
||||
{
|
||||
return isInterruptionRequested();
|
||||
}
|
||||
|
||||
void CoverDownloadThread::SetTitle(const std::string_view title)
|
||||
{
|
||||
emit titleUpdated(QtUtils::StringViewToQString(title));
|
||||
}
|
||||
|
||||
void CoverDownloadThread::SetStatusText(const std::string_view text)
|
||||
{
|
||||
ProgressCallback::SetStatusText(text);
|
||||
emit statusUpdated(QtUtils::StringViewToQString(text));
|
||||
}
|
||||
|
||||
void CoverDownloadThread::SetProgressRange(u32 range)
|
||||
{
|
||||
ProgressCallback::SetProgressRange(range);
|
||||
emit progressUpdated(static_cast<int>(m_progress_value), static_cast<int>(m_progress_range));
|
||||
}
|
||||
|
||||
void CoverDownloadThread::SetProgressValue(u32 value)
|
||||
{
|
||||
ProgressCallback::SetProgressValue(value);
|
||||
emit progressUpdated(static_cast<int>(m_progress_value), static_cast<int>(m_progress_range));
|
||||
}
|
||||
|
||||
void CoverDownloadThread::run()
|
||||
{
|
||||
m_result = GameList::DownloadCovers(m_urls, m_use_serials, static_cast<ProgressCallback*>(this), &m_error);
|
||||
emit threadFinished();
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
#include "ui_coverdownloadwindow.h"
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/progress_callback.h"
|
||||
#include "common/timer.h"
|
||||
#include "common/types.h"
|
||||
|
||||
@@ -16,7 +14,9 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class CoverDownloadThread;
|
||||
class Error;
|
||||
|
||||
class QtAsyncTaskWithProgress;
|
||||
|
||||
class CoverDownloadWindow final : public QWidget
|
||||
{
|
||||
@@ -34,50 +34,11 @@ protected:
|
||||
void closeEvent(QCloseEvent* ev) override;
|
||||
|
||||
private:
|
||||
void startThread();
|
||||
void cancelThread();
|
||||
|
||||
void onDownloadStatus(const QString& text);
|
||||
void onDownloadProgress(int value, int range);
|
||||
void onDownloadComplete();
|
||||
void onStartClicked();
|
||||
void onCloseClicked();
|
||||
void downloadComplete(bool result, const Error& error);
|
||||
void updateEnabled();
|
||||
|
||||
Ui::CoverDownloadWindow m_ui;
|
||||
CoverDownloadThread* m_thread = nullptr;
|
||||
QtAsyncTaskWithProgress* m_task = nullptr;
|
||||
Timer m_last_refresh_time;
|
||||
};
|
||||
|
||||
class CoverDownloadThread final : public QThread, private ProgressCallback
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CoverDownloadThread(const QString& urls, bool use_serials);
|
||||
~CoverDownloadThread();
|
||||
|
||||
ALWAYS_INLINE const Error& getError() const { return m_error; }
|
||||
ALWAYS_INLINE bool getResult() const { return m_result; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void titleUpdated(const QString& title);
|
||||
void statusUpdated(const QString& status);
|
||||
void progressUpdated(int value, int range);
|
||||
void threadFinished();
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
bool IsCancelled() const override;
|
||||
void SetTitle(const std::string_view title) override;
|
||||
void SetStatusText(const std::string_view text) override;
|
||||
void SetProgressRange(u32 range) override;
|
||||
void SetProgressValue(u32 value) override;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_urls;
|
||||
Error m_error;
|
||||
bool m_use_serials = false;
|
||||
bool m_result = false;
|
||||
};
|
||||
Reference in New Issue
Block a user