Qt: Add cover downloader
This commit is contained in:
parent
21b7261dc9
commit
389143db64
|
@ -48,6 +48,9 @@ set(SRCS
|
||||||
controllersettingsdialog.h
|
controllersettingsdialog.h
|
||||||
controllersettingsdialog.ui
|
controllersettingsdialog.ui
|
||||||
controllersettingwidgetbinder.h
|
controllersettingwidgetbinder.h
|
||||||
|
coverdownloaddialog.cpp
|
||||||
|
coverdownloaddialog.h
|
||||||
|
coverdownloaddialog.ui
|
||||||
debuggermodels.cpp
|
debuggermodels.cpp
|
||||||
debuggermodels.h
|
debuggermodels.h
|
||||||
debuggerwindow.cpp
|
debuggerwindow.cpp
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
#include "coverdownloaddialog.h"
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "frontend-common/game_list.h"
|
||||||
|
|
||||||
|
CoverDownloadDialog::CoverDownloadDialog(QWidget* parent /*= nullptr*/) : QDialog(parent)
|
||||||
|
{
|
||||||
|
m_ui.setupUi(this);
|
||||||
|
updateEnabled();
|
||||||
|
|
||||||
|
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadDialog::onStartClicked);
|
||||||
|
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadDialog::onCloseClicked);
|
||||||
|
connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadDialog::updateEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoverDownloadDialog::~CoverDownloadDialog()
|
||||||
|
{
|
||||||
|
Assert(!m_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::closeEvent(QCloseEvent* ev)
|
||||||
|
{
|
||||||
|
cancelThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::onDownloadStatus(const QString& text)
|
||||||
|
{
|
||||||
|
m_ui.status->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::onDownloadProgress(int value, int range)
|
||||||
|
{
|
||||||
|
// limit to once every five seconds
|
||||||
|
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 CoverDownloadDialog::onDownloadComplete()
|
||||||
|
{
|
||||||
|
emit coverRefreshRequested();
|
||||||
|
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
m_thread->join();
|
||||||
|
m_thread.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEnabled();
|
||||||
|
|
||||||
|
m_ui.status->setText(tr("Download complete."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::onStartClicked()
|
||||||
|
{
|
||||||
|
if (m_thread)
|
||||||
|
cancelThread();
|
||||||
|
else
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::onCloseClicked()
|
||||||
|
{
|
||||||
|
if (m_thread)
|
||||||
|
cancelThread();
|
||||||
|
|
||||||
|
done(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::updateEnabled()
|
||||||
|
{
|
||||||
|
const bool running = static_cast<bool>(m_thread);
|
||||||
|
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 CoverDownloadDialog::startThread()
|
||||||
|
{
|
||||||
|
m_thread = std::make_unique<CoverDownloadThread>(this, m_ui.urls->toPlainText());
|
||||||
|
connect(m_thread.get(), &CoverDownloadThread::statusUpdated, this, &CoverDownloadDialog::onDownloadStatus);
|
||||||
|
connect(m_thread.get(), &CoverDownloadThread::progressUpdated, this, &CoverDownloadDialog::onDownloadProgress);
|
||||||
|
connect(m_thread.get(), &CoverDownloadThread::threadFinished, this, &CoverDownloadDialog::onDownloadComplete);
|
||||||
|
m_thread->start();
|
||||||
|
updateEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverDownloadDialog::cancelThread()
|
||||||
|
{
|
||||||
|
if (!m_thread)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_thread->requestInterruption();
|
||||||
|
m_thread->join();
|
||||||
|
m_thread.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
CoverDownloadDialog::CoverDownloadThread::CoverDownloadThread(QWidget* parent, const QString& urls)
|
||||||
|
: QtAsyncProgressThread(parent)
|
||||||
|
{
|
||||||
|
for (const QString& str : urls.split(QChar('\n')))
|
||||||
|
m_urls.push_back(str.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
CoverDownloadDialog::CoverDownloadThread::~CoverDownloadThread() = default;
|
||||||
|
|
||||||
|
void CoverDownloadDialog::CoverDownloadThread::runAsync()
|
||||||
|
{
|
||||||
|
GameList::DownloadCovers(m_urls, this);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/timer.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "qtprogresscallback.h"
|
||||||
|
#include "ui_coverdownloaddialog.h"
|
||||||
|
#include <QtWidgets/QDialog>
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CoverDownloadDialog final : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoverDownloadDialog(QWidget* parent = nullptr);
|
||||||
|
~CoverDownloadDialog();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void coverRefreshRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent* ev);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onDownloadStatus(const QString& text);
|
||||||
|
void onDownloadProgress(int value, int range);
|
||||||
|
void onDownloadComplete();
|
||||||
|
void onStartClicked();
|
||||||
|
void onCloseClicked();
|
||||||
|
void updateEnabled();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class CoverDownloadThread : public QtAsyncProgressThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CoverDownloadThread(QWidget* parent, const QString& urls);
|
||||||
|
~CoverDownloadThread();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void runAsync() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_urls;
|
||||||
|
};
|
||||||
|
|
||||||
|
void startThread();
|
||||||
|
void cancelThread();
|
||||||
|
|
||||||
|
Ui::CoverDownloadDialog m_ui;
|
||||||
|
std::unique_ptr<CoverDownloadThread> m_thread;
|
||||||
|
Common::Timer m_last_refresh_time;
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CoverDownloadDialog</class>
|
||||||
|
<widget class="QDialog" name="CoverDownloadDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>656</width>
|
||||||
|
<height>343</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Download Covers</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>DuckStation can automatically download covers for games which do not currently have a cover set. We do not host any cover images, the user must provide their own source for images.</p><p>In the form below, specify the URLs to download covers from, with one template URL per line. The following variables are available:</p><p><span style=" font-style:italic;">${title}:</span> Title of the game.<br/><span style=" font-style:italic;">${filetitle}:</span> Name component of the game's filename.<br/><span style=" font-style:italic;">${serial}:</span> Serial of the game.</p><p><span style=" font-weight:700;">Example:</span> https://www.example-not-a-real-domain.com/covers/${serial}.jpg</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="urls"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="status">
|
||||||
|
<property name="text">
|
||||||
|
<string>Waiting to start...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progress"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="start">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="close">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -16,6 +16,7 @@
|
||||||
<ClCompile Include="controllerbindingwidgets.cpp" />
|
<ClCompile Include="controllerbindingwidgets.cpp" />
|
||||||
<ClCompile Include="controllerglobalsettingswidget.cpp" />
|
<ClCompile Include="controllerglobalsettingswidget.cpp" />
|
||||||
<ClCompile Include="controllersettingsdialog.cpp" />
|
<ClCompile Include="controllersettingsdialog.cpp" />
|
||||||
|
<ClCompile Include="coverdownloaddialog.cpp" />
|
||||||
<ClCompile Include="emulationsettingswidget.cpp" />
|
<ClCompile Include="emulationsettingswidget.cpp" />
|
||||||
<ClCompile Include="debuggermodels.cpp" />
|
<ClCompile Include="debuggermodels.cpp" />
|
||||||
<ClCompile Include="debuggerwindow.cpp" />
|
<ClCompile Include="debuggerwindow.cpp" />
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
<QtMoc Include="biossettingswidget.h" />
|
<QtMoc Include="biossettingswidget.h" />
|
||||||
<QtMoc Include="cheatmanagerdialog.h" />
|
<QtMoc Include="cheatmanagerdialog.h" />
|
||||||
<QtMoc Include="cheatcodeeditordialog.h" />
|
<QtMoc Include="cheatcodeeditordialog.h" />
|
||||||
|
<QtMoc Include="coverdownloaddialog.h" />
|
||||||
<QtMoc Include="enhancementsettingswidget.h" />
|
<QtMoc Include="enhancementsettingswidget.h" />
|
||||||
<QtMoc Include="memorycardsettingswidget.h" />
|
<QtMoc Include="memorycardsettingswidget.h" />
|
||||||
<QtMoc Include="memorycardeditordialog.h" />
|
<QtMoc Include="memorycardeditordialog.h" />
|
||||||
|
@ -210,6 +212,9 @@
|
||||||
<QtUi Include="foldersettingswidget.ui">
|
<QtUi Include="foldersettingswidget.ui">
|
||||||
<FileType>Document</FileType>
|
<FileType>Document</FileType>
|
||||||
</QtUi>
|
</QtUi>
|
||||||
|
<QtUi Include="coverdownloaddialog.ui">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
</QtUi>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtResource Include="resources\resources.qrc">
|
<QtResource Include="resources\resources.qrc">
|
||||||
|
@ -231,6 +236,7 @@
|
||||||
<ClCompile Include="$(IntDir)moc_controllerbindingwidgets.cpp" />
|
<ClCompile Include="$(IntDir)moc_controllerbindingwidgets.cpp" />
|
||||||
<ClCompile Include="$(IntDir)moc_controllerglobalsettingswidget.cpp" />
|
<ClCompile Include="$(IntDir)moc_controllerglobalsettingswidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)moc_controllersettingsdialog.cpp" />
|
<ClCompile Include="$(IntDir)moc_controllersettingsdialog.cpp" />
|
||||||
|
<ClCompile Include="$(IntDir)moc_coverdownloaddialog.cpp" />
|
||||||
<ClCompile Include="$(IntDir)moc_displaywidget.cpp" />
|
<ClCompile Include="$(IntDir)moc_displaywidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" />
|
<ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" />
|
<ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" />
|
||||||
|
|
|
@ -220,7 +220,7 @@ void GameSummaryWidget::onComputeHashClicked()
|
||||||
QtConcurrent::run([]() { return &GameDatabase::GetTrackHashesMap(); });
|
QtConcurrent::run([]() { return &GameDatabase::GetTrackHashesMap(); });
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QtProgressCallback progress_callback(this);
|
QtModalProgressCallback progress_callback(this);
|
||||||
progress_callback.SetProgressRange(image->GetTrackCount());
|
progress_callback.SetProgressRange(image->GetTrackCount());
|
||||||
|
|
||||||
std::vector<CDImageHasher::Hash> track_hashes;
|
std::vector<CDImageHasher::Hash> track_hashes;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "core/memory_card.h"
|
#include "core/memory_card.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
|
#include "coverdownloaddialog.h"
|
||||||
#include "debuggerwindow.h"
|
#include "debuggerwindow.h"
|
||||||
#include "displaywidget.h"
|
#include "displaywidget.h"
|
||||||
#include "frontend-common/game_list.h"
|
#include "frontend-common/game_list.h"
|
||||||
|
@ -1828,6 +1829,7 @@ void MainWindow::connectSignals()
|
||||||
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
||||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
||||||
connect(m_ui.actionMemory_Card_Editor, &QAction::triggered, this, &MainWindow::onToolsMemoryCardEditorTriggered);
|
connect(m_ui.actionMemory_Card_Editor, &QAction::triggered, this, &MainWindow::onToolsMemoryCardEditorTriggered);
|
||||||
|
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||||
connect(m_ui.actionCheatManager, &QAction::triggered, this, &MainWindow::onToolsCheatManagerTriggered);
|
connect(m_ui.actionCheatManager, &QAction::triggered, this, &MainWindow::onToolsCheatManagerTriggered);
|
||||||
connect(m_ui.actionCPUDebugger, &QAction::triggered, this, &MainWindow::openCPUDebugger);
|
connect(m_ui.actionCPUDebugger, &QAction::triggered, this, &MainWindow::openCPUDebugger);
|
||||||
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
||||||
|
@ -2521,6 +2523,13 @@ void MainWindow::onToolsMemoryCardEditorTriggered()
|
||||||
openMemoryCardEditor(QString(), QString());
|
openMemoryCardEditor(QString(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onToolsCoverDownloaderTriggered()
|
||||||
|
{
|
||||||
|
CoverDownloadDialog dlg(this);
|
||||||
|
connect(&dlg, &CoverDownloadDialog::coverRefreshRequested, m_game_list_widget, &GameListWidget::refreshGridCovers);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onToolsCheatManagerTriggered()
|
void MainWindow::onToolsCheatManagerTriggered()
|
||||||
{
|
{
|
||||||
if (!m_cheat_manager_dialog)
|
if (!m_cheat_manager_dialog)
|
||||||
|
|
|
@ -147,6 +147,7 @@ private Q_SLOTS:
|
||||||
void onAboutActionTriggered();
|
void onAboutActionTriggered();
|
||||||
void onCheckForUpdatesActionTriggered();
|
void onCheckForUpdatesActionTriggered();
|
||||||
void onToolsMemoryCardEditorTriggered();
|
void onToolsMemoryCardEditorTriggered();
|
||||||
|
void onToolsCoverDownloaderTriggered();
|
||||||
void onToolsCheatManagerTriggered();
|
void onToolsCheatManagerTriggered();
|
||||||
void onToolsOpenDataDirectoryTriggered();
|
void onToolsOpenDataDirectoryTriggered();
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
<string>DuckStation</string>
|
<string>DuckStation</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
|
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QStackedWidget" name="mainContainer" />
|
<widget class="QStackedWidget" name="mainContainer"/>
|
||||||
<widget class="QMenuBar" name="menuBar">
|
<widget class="QMenuBar" name="menuBar">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
|
@ -105,7 +105,8 @@
|
||||||
<string>Theme</string>
|
<string>Theme</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="paint-brush-line"/>
|
<iconset theme="paint-brush-line">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuSettingsLanguage">
|
<widget class="QMenu" name="menuSettingsLanguage">
|
||||||
|
@ -113,7 +114,8 @@
|
||||||
<string>Language</string>
|
<string>Language</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="global-line"/>
|
<iconset theme="global-line">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -229,6 +231,7 @@
|
||||||
<string>&Tools</string>
|
<string>&Tools</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionMemory_Card_Editor"/>
|
<addaction name="actionMemory_Card_Editor"/>
|
||||||
|
<addaction name="actionCoverDownloader"/>
|
||||||
<addaction name="actionCheatManager"/>
|
<addaction name="actionCheatManager"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionOpenDataDirectory"/>
|
<addaction name="actionOpenDataDirectory"/>
|
||||||
|
@ -468,7 +471,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGitHubRepository">
|
<action name="actionGitHubRepository">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/github.png</normaloff>:/icons/github.png</iconset>
|
<normaloff>:/icons/github.png</normaloff>:/icons/github.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -477,7 +480,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionIssueTracker">
|
<action name="actionIssueTracker">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/IssueTracker.png</normaloff>:/icons/IssueTracker.png</iconset>
|
<normaloff>:/icons/IssueTracker.png</normaloff>:/icons/IssueTracker.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -486,7 +489,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDiscordServer">
|
<action name="actionDiscordServer">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/discord.png</normaloff>:/icons/discord.png</iconset>
|
<normaloff>:/icons/discord.png</normaloff>:/icons/discord.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -504,7 +507,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAboutQt">
|
<action name="actionAboutQt">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/QT.png</normaloff>:/icons/QT.png</iconset>
|
<normaloff>:/icons/QT.png</normaloff>:/icons/QT.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -513,7 +516,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAbout">
|
<action name="actionAbout">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/duck_64.png</normaloff>:/icons/duck_64.png</iconset>
|
<normaloff>:/icons/duck_64.png</normaloff>:/icons/duck_64.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -940,6 +943,11 @@
|
||||||
<string>Big Picture</string>
|
<string>Big Picture</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionCoverDownloader">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cover Downloader</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="resources/resources.qrc"/>
|
<include location="resources/resources.qrc"/>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "qtprogresscallback.h"
|
#include "qtprogresscallback.h"
|
||||||
|
#include "common/assert.h"
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtWidgets/QMessageBox>
|
#include <QtWidgets/QMessageBox>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
QtProgressCallback::QtProgressCallback(QWidget* parent_widget, float show_delay)
|
QtModalProgressCallback::QtModalProgressCallback(QWidget* parent_widget, float show_delay)
|
||||||
: QObject(parent_widget), m_dialog(QString(), QString(), 0, 1, parent_widget), m_show_delay(show_delay)
|
: QObject(parent_widget), m_dialog(QString(), QString(), 0, 1, parent_widget), m_show_delay(show_delay)
|
||||||
{
|
{
|
||||||
m_dialog.setWindowTitle(tr("DuckStation"));
|
m_dialog.setWindowTitle(tr("DuckStation"));
|
||||||
|
@ -15,14 +16,14 @@ QtProgressCallback::QtProgressCallback(QWidget* parent_widget, float show_delay)
|
||||||
checkForDelayedShow();
|
checkForDelayedShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
QtProgressCallback::~QtProgressCallback() = default;
|
QtModalProgressCallback::~QtModalProgressCallback() = default;
|
||||||
|
|
||||||
bool QtProgressCallback::IsCancelled() const
|
bool QtModalProgressCallback::IsCancelled() const
|
||||||
{
|
{
|
||||||
return m_dialog.wasCanceled();
|
return m_dialog.wasCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::SetCancellable(bool cancellable)
|
void QtModalProgressCallback::SetCancellable(bool cancellable)
|
||||||
{
|
{
|
||||||
if (m_cancellable == cancellable)
|
if (m_cancellable == cancellable)
|
||||||
return;
|
return;
|
||||||
|
@ -31,12 +32,12 @@ void QtProgressCallback::SetCancellable(bool cancellable)
|
||||||
m_dialog.setCancelButtonText(cancellable ? tr("Cancel") : QString());
|
m_dialog.setCancelButtonText(cancellable ? tr("Cancel") : QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::SetTitle(const char* title)
|
void QtModalProgressCallback::SetTitle(const char* title)
|
||||||
{
|
{
|
||||||
m_dialog.setWindowTitle(QString::fromUtf8(title));
|
m_dialog.setWindowTitle(QString::fromUtf8(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::SetStatusText(const char* text)
|
void QtModalProgressCallback::SetStatusText(const char* text)
|
||||||
{
|
{
|
||||||
BaseProgressCallback::SetStatusText(text);
|
BaseProgressCallback::SetStatusText(text);
|
||||||
checkForDelayedShow();
|
checkForDelayedShow();
|
||||||
|
@ -45,7 +46,7 @@ void QtProgressCallback::SetStatusText(const char* text)
|
||||||
m_dialog.setLabelText(QString::fromUtf8(text));
|
m_dialog.setLabelText(QString::fromUtf8(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::SetProgressRange(u32 range)
|
void QtModalProgressCallback::SetProgressRange(u32 range)
|
||||||
{
|
{
|
||||||
BaseProgressCallback::SetProgressRange(range);
|
BaseProgressCallback::SetProgressRange(range);
|
||||||
checkForDelayedShow();
|
checkForDelayedShow();
|
||||||
|
@ -54,7 +55,7 @@ void QtProgressCallback::SetProgressRange(u32 range)
|
||||||
m_dialog.setRange(0, m_progress_range);
|
m_dialog.setRange(0, m_progress_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::SetProgressValue(u32 value)
|
void QtModalProgressCallback::SetProgressValue(u32 value)
|
||||||
{
|
{
|
||||||
BaseProgressCallback::SetProgressValue(value);
|
BaseProgressCallback::SetProgressValue(value);
|
||||||
checkForDelayedShow();
|
checkForDelayedShow();
|
||||||
|
@ -65,43 +66,43 @@ void QtProgressCallback::SetProgressValue(u32 value)
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::DisplayError(const char* message)
|
void QtModalProgressCallback::DisplayError(const char* message)
|
||||||
{
|
{
|
||||||
qWarning() << message;
|
qWarning() << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::DisplayWarning(const char* message)
|
void QtModalProgressCallback::DisplayWarning(const char* message)
|
||||||
{
|
{
|
||||||
qWarning() << message;
|
qWarning() << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::DisplayInformation(const char* message)
|
void QtModalProgressCallback::DisplayInformation(const char* message)
|
||||||
{
|
{
|
||||||
qWarning() << message;
|
qWarning() << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::DisplayDebugMessage(const char* message)
|
void QtModalProgressCallback::DisplayDebugMessage(const char* message)
|
||||||
{
|
{
|
||||||
qWarning() << message;
|
qWarning() << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::ModalError(const char* message)
|
void QtModalProgressCallback::ModalError(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(&m_dialog, tr("Error"), QString::fromUtf8(message));
|
QMessageBox::critical(&m_dialog, tr("Error"), QString::fromUtf8(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QtProgressCallback::ModalConfirmation(const char* message)
|
bool QtModalProgressCallback::ModalConfirmation(const char* message)
|
||||||
{
|
{
|
||||||
return (QMessageBox::question(&m_dialog, tr("Question"), QString::fromUtf8(message), QMessageBox::Yes,
|
return (QMessageBox::question(&m_dialog, tr("Question"), QString::fromUtf8(message), QMessageBox::Yes,
|
||||||
QMessageBox::No) == QMessageBox::Yes);
|
QMessageBox::No) == QMessageBox::Yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::ModalInformation(const char* message)
|
void QtModalProgressCallback::ModalInformation(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::information(&m_dialog, tr("Information"), QString::fromUtf8(message));
|
QMessageBox::information(&m_dialog, tr("Information"), QString::fromUtf8(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtProgressCallback::checkForDelayedShow()
|
void QtModalProgressCallback::checkForDelayedShow()
|
||||||
{
|
{
|
||||||
if (m_dialog.isVisible())
|
if (m_dialog.isVisible())
|
||||||
return;
|
return;
|
||||||
|
@ -113,3 +114,109 @@ void QtProgressCallback::checkForDelayedShow()
|
||||||
m_dialog.show();
|
m_dialog.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtAsyncProgressThread::QtAsyncProgressThread(QWidget* parent) : QThread(parent) {}
|
||||||
|
|
||||||
|
QtAsyncProgressThread::~QtAsyncProgressThread() = default;
|
||||||
|
|
||||||
|
bool QtAsyncProgressThread::IsCancelled() const
|
||||||
|
{
|
||||||
|
return isInterruptionRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::SetCancellable(bool cancellable)
|
||||||
|
{
|
||||||
|
if (m_cancellable == cancellable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BaseProgressCallback::SetCancellable(cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::SetTitle(const char* title)
|
||||||
|
{
|
||||||
|
emit titleUpdated(QString::fromUtf8(title));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::SetStatusText(const char* text)
|
||||||
|
{
|
||||||
|
BaseProgressCallback::SetStatusText(text);
|
||||||
|
emit statusUpdated(QString::fromUtf8(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::SetProgressRange(u32 range)
|
||||||
|
{
|
||||||
|
BaseProgressCallback::SetProgressRange(range);
|
||||||
|
emit progressUpdated(static_cast<int>(m_progress_value), static_cast<int>(m_progress_range));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::SetProgressValue(u32 value)
|
||||||
|
{
|
||||||
|
BaseProgressCallback::SetProgressValue(value);
|
||||||
|
emit progressUpdated(static_cast<int>(m_progress_value), static_cast<int>(m_progress_range));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::DisplayError(const char* message)
|
||||||
|
{
|
||||||
|
qWarning() << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::DisplayWarning(const char* message)
|
||||||
|
{
|
||||||
|
qWarning() << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::DisplayInformation(const char* message)
|
||||||
|
{
|
||||||
|
qWarning() << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::DisplayDebugMessage(const char* message)
|
||||||
|
{
|
||||||
|
qWarning() << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::ModalError(const char* message)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(parentWidget(), tr("Error"), QString::fromUtf8(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtAsyncProgressThread::ModalConfirmation(const char* message)
|
||||||
|
{
|
||||||
|
return (QMessageBox::question(parentWidget(), tr("Question"), QString::fromUtf8(message), QMessageBox::Yes,
|
||||||
|
QMessageBox::No) == QMessageBox::Yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::ModalInformation(const char* message)
|
||||||
|
{
|
||||||
|
QMessageBox::information(parentWidget(), tr("Information"), QString::fromUtf8(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::start()
|
||||||
|
{
|
||||||
|
Assert(!isRunning());
|
||||||
|
|
||||||
|
QThread::start();
|
||||||
|
moveToThread(this);
|
||||||
|
m_starting_thread = QThread::currentThread();
|
||||||
|
m_start_semaphore.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::join()
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
QThread::wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAsyncProgressThread::run()
|
||||||
|
{
|
||||||
|
m_start_semaphore.acquire();
|
||||||
|
emit threadStarting();
|
||||||
|
runAsync();
|
||||||
|
emit threadFinished();
|
||||||
|
moveToThread(m_starting_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* QtAsyncProgressThread::parentWidget() const
|
||||||
|
{
|
||||||
|
return qobject_cast<QWidget*>(parent());
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
#include "common/timer.h"
|
#include "common/timer.h"
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
#include <QtCore/QSemaphore>
|
||||||
#include <QtWidgets/QProgressDialog>
|
#include <QtWidgets/QProgressDialog>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
class QtProgressCallback final : public QObject, public BaseProgressCallback
|
class QtModalProgressCallback final : public QObject, public BaseProgressCallback
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QtProgressCallback(QWidget* parent_widget, float show_delay = 0.0f);
|
QtModalProgressCallback(QWidget* parent_widget, float show_delay = 0.0f);
|
||||||
~QtProgressCallback();
|
~QtModalProgressCallback();
|
||||||
|
|
||||||
bool IsCancelled() const override;
|
bool IsCancelled() const override;
|
||||||
|
|
||||||
|
@ -34,4 +37,51 @@ private:
|
||||||
QProgressDialog m_dialog;
|
QProgressDialog m_dialog;
|
||||||
Common::Timer m_show_timer;
|
Common::Timer m_show_timer;
|
||||||
float m_show_delay;
|
float m_show_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QtAsyncProgressThread : public QThread, public BaseProgressCallback
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtAsyncProgressThread(QWidget* parent);
|
||||||
|
~QtAsyncProgressThread();
|
||||||
|
|
||||||
|
bool IsCancelled() const override;
|
||||||
|
|
||||||
|
void SetCancellable(bool cancellable) override;
|
||||||
|
void SetTitle(const char* title) override;
|
||||||
|
void SetStatusText(const char* text) override;
|
||||||
|
void SetProgressRange(u32 range) override;
|
||||||
|
void SetProgressValue(u32 value) override;
|
||||||
|
|
||||||
|
void DisplayError(const char* message) override;
|
||||||
|
void DisplayWarning(const char* message) override;
|
||||||
|
void DisplayInformation(const char* message) override;
|
||||||
|
void DisplayDebugMessage(const char* message) override;
|
||||||
|
|
||||||
|
void ModalError(const char* message) override;
|
||||||
|
bool ModalConfirmation(const char* message) override;
|
||||||
|
void ModalInformation(const char* message) override;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void titleUpdated(const QString& title);
|
||||||
|
void statusUpdated(const QString& status);
|
||||||
|
void progressUpdated(int value, int range);
|
||||||
|
void threadStarting();
|
||||||
|
void threadFinished();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void start();
|
||||||
|
void join();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void runAsync() = 0;
|
||||||
|
void run() final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget* parentWidget() const;
|
||||||
|
|
||||||
|
QSemaphore m_start_semaphore;
|
||||||
|
QThread* m_starting_thread = nullptr;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue