From e9e424ec828521d82e55e91b42c114741991666f Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 25 Aug 2018 01:00:18 -0400 Subject: [PATCH] Qt: add right-click option to download thumbnail for playlist entries --- Makefile.common | 3 +- griffin/griffin_cpp.cpp | 1 + intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 4 + msg_hash.h | 2 + ui/drivers/qt/filedropwidget.cpp | 28 ++- ui/drivers/qt/playlist.cpp | 1 + ui/drivers/qt/shaderparamsdialog.cpp | 8 +- ui/drivers/qt/thumbnaildownload.cpp | 294 +++++++++++++++++++++++++++ ui/drivers/qt/ui_qt_window.cpp | 32 ++- ui/drivers/qt/updateretroarch.cpp | 1 + ui/drivers/ui_qt.h | 17 ++ 12 files changed, 387 insertions(+), 8 deletions(-) create mode 100644 ui/drivers/qt/thumbnaildownload.cpp diff --git a/Makefile.common b/Makefile.common index 7721c15c32..09ab22222d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -346,7 +346,8 @@ OBJ += ui/drivers/ui_qt.o \ ui/drivers/qt/playlistentrydialog.o \ ui/drivers/qt/viewoptionsdialog.o \ ui/drivers/qt/playlist.o \ - ui/drivers/qt/updateretroarch.o + ui/drivers/qt/updateretroarch.o \ + ui/drivers/qt/thumbnaildownload.o MOC_HEADERS += ui/drivers/ui_qt.h \ ui/drivers/qt/ui_qt_load_core_window.h \ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index a51280b7bf..5c75dfefdb 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -49,6 +49,7 @@ UI #include "../ui/drivers/qt/viewoptionsdialog.cpp" #include "../ui/drivers/qt/playlist.cpp" #include "../ui/drivers/qt/updateretroarch.cpp" +#include "../ui/drivers/qt/thumbnaildownload.cpp" #endif /*============================================================ diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 597e09af19..de56179467 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3788,3 +3788,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, "すべてのパスをリセット") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "パラメータをリセット") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "サムネイルをダウンロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "他のダウンロードが実行中です。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 31c4293bf1..675a4809eb 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7386,3 +7386,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Reset Parameter" ) +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + "Download thumbnail") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, + "A download is already in progress.") diff --git a/msg_hash.h b/msg_hash.h index 1ee633ba07..e87319e4de 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2004,6 +2004,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL, + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/filedropwidget.cpp b/ui/drivers/qt/filedropwidget.cpp index 0d3809b668..bf5fc32d64 100644 --- a/ui/drivers/qt/filedropwidget.cpp +++ b/ui/drivers/qt/filedropwidget.cpp @@ -81,6 +81,7 @@ void FileDropWidget::dropEvent(QDropEvent *event) void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) { QScopedPointer menu; + QScopedPointer downloadThumbnailAction; QScopedPointer addEntryAction; QScopedPointer addFilesAction; QScopedPointer addFolderAction; @@ -92,12 +93,14 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) menu.reset(new QMenu(this)); + downloadThumbnailAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL)), this)); addEntryAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY)), this)); addFilesAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FILES)), this)); addFolderAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADD_FOLDER)), this)); editAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_EDIT)), this)); deleteAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE)), this)); + menu->addAction(downloadThumbnailAction.data()); menu->addAction(addEntryAction.data()); menu->addAction(addFilesAction.data()); menu->addAction(addFolderAction.data()); @@ -113,7 +116,30 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos) if (!selectedAction) return; - if (selectedAction == addFilesAction.data()) + if (selectedAction == downloadThumbnailAction.data()) + { + QHash hash = getCurrentContentHash(); + QString system = QFileInfo(getCurrentPlaylistPath()).completeBaseName(); + QString path = hash.value("label"); + + if (!path.isEmpty()) + { + QString title = QFileInfo(path).completeBaseName(); + + if (m_pendingThumbnailDownloadTypes.isEmpty()) + { + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_BOXART); + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_SCREENSHOT); + m_pendingThumbnailDownloadTypes.append(THUMBNAIL_TITLE); + downloadThumbnail(system, title); + } + else + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + } + } + } + else if (selectedAction == addFilesAction.data()) { QStringList filePaths = QFileDialog::getOpenFileNames(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_FILES)); diff --git a/ui/drivers/qt/playlist.cpp b/ui/drivers/qt/playlist.cpp index f2f1e4ef86..7113500f3d 100644 --- a/ui/drivers/qt/playlist.cpp +++ b/ui/drivers/qt/playlist.cpp @@ -992,6 +992,7 @@ void MainWindow::addPlaylistHashToGrid(const QVector > & item->widget->setLayout(new QVBoxLayout()); item->widget->setObjectName("thumbnailWidget"); item->widget->setProperty("hash", QVariant::fromValue >(hash)); + item->widget->setProperty("image_path", imagePath); connect(item->widget, SIGNAL(mouseDoubleClicked()), this, SLOT(onGridItemDoubleClicked())); connect(item->widget, SIGNAL(mousePressed()), this, SLOT(onGridItemClicked())); diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 2ed8ecdaf4..cffcd85498 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -1339,7 +1339,7 @@ void ShaderParamsDialog::onShaderParamCheckBoxClicked() struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1399,7 +1399,7 @@ void ShaderParamsDialog::onShaderParamSliderValueChanged(int) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1500,7 +1500,7 @@ void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; @@ -1580,7 +1580,7 @@ void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value) struct video_shader_parameter *param = NULL; int i; - for (i = 0; i < video_shader->num_parameters; i++) + for (i = 0; i < static_cast(video_shader->num_parameters); i++) { QString id = video_shader->parameters[i].id; diff --git a/ui/drivers/qt/thumbnaildownload.cpp b/ui/drivers/qt/thumbnaildownload.cpp new file mode 100644 index 0000000000..4094cd495d --- /dev/null +++ b/ui/drivers/qt/thumbnaildownload.cpp @@ -0,0 +1,294 @@ +#include +#include +#include + +#include "../ui_qt.h" + +extern "C" { +#include +#include +#include +#include "../../../tasks/tasks_internal.h" +#include "../../../verbosity.h" +#include "../../../config.def.h" +#include "../../../configuration.h" +#include "../../../version.h" +} + +#define USER_AGENT "RetroArch-WIMP/" PACKAGE_VERSION +#define PARTIAL_EXTENSION ".partial" +#define TEMP_EXTENSION ".tmp" +#define THUMBNAIL_URL_HEADER "https://github.com/libretro-thumbnails/" +#define THUMBNAIL_URL_BRANCH "/blob/master/" +#define THUMBNAIL_IMAGE_EXTENSION ".png" +#define THUMBNAIL_URL_FOOTER THUMBNAIL_IMAGE_EXTENSION "?raw=true" + +void MainWindow::onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + QByteArray errorStringArray; + const char *errorStringData = NULL; + + m_thumbnailDownloadProgressDialog->cancel(); + + if (!reply) + return; + + errorStringArray = reply->errorString().toUtf8(); + errorStringData = errorStringArray.constData(); + + RARCH_ERR("[Qt]: Network error code %d received: %s\n", code, errorStringData); + + /* Deleting the reply here seems to cause a strange heap-use-after-free crash. */ + /* + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + */ +} + +void MainWindow::onThumbnailDownloadNetworkSslErrors(const QList &errors) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + int i; + + if (!reply) + return; + + for (i = 0; i < errors.count(); i++) + { + const QSslError &error = errors.at(i); + QString string = QString("Ignoring SSL error code ") + QString::number(error.error()) + ": " + error.errorString(); + QByteArray stringArray = string.toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: %s\n", stringData); + } + + /* ignore all SSL errors for now, like self-signed, expired etc. */ + reply->ignoreSslErrors(); +} + +void MainWindow::onThumbnailDownloadCanceled() +{ + m_thumbnailDownloadProgressDialog->cancel(); +} + +void MainWindow::onThumbnailDownloadFinished() +{ + QString system; + QString title; + QString downloadType; + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + QNetworkReply::NetworkError error; + int code; + + m_thumbnailDownloadProgressDialog->cancel(); + + /* At least on Linux, the progress dialog will refuse to hide itself and will stay on screen in a corrupted way if we happen to show an error message in this function. processEvents() will sometimes fix it, other times not... seems random. */ + qApp->processEvents(); + + if (!reply) + return; + + system = reply->property("system").toString(); + title = reply->property("title").toString(); + downloadType = reply->property("download_type").toString(); + + error = reply->error(); + code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_thumbnailDownloadFile.isOpen()) + m_thumbnailDownloadFile.close(); + + if (code != 200) + { + QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + + if (!redirectUrl.isEmpty()) + { + QByteArray redirectUrlArray = redirectUrl.toString().toUtf8(); + const char *redirectUrlData = redirectUrlArray.constData(); + + m_pendingThumbnailDownloadTypes.prepend(downloadType); + + RARCH_LOG("[Qt]: Thumbnail download got redirect with HTTP code %d: %s\n", code, redirectUrlData); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + downloadThumbnail(system, title, redirectUrl); + + return; + } + else + { + /*emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code));*/ + + RARCH_ERR("[Qt]: Thumbnail download failed with HTTP status code: %d\n", code); + + reply->disconnect(); + reply->abort(); + reply->deleteLater(); + + if (!m_pendingThumbnailDownloadTypes.isEmpty()) + downloadThumbnail(system, title); + + return; + } + } + + if (error == QNetworkReply::NoError) + { + int index = m_thumbnailDownloadFile.fileName().lastIndexOf(PARTIAL_EXTENSION); + QString newFileName = m_thumbnailDownloadFile.fileName().left(index); + QFile newFile(newFileName); + + /* rename() requires the old file to be deleted first if it exists */ + if (newFile.exists() && !newFile.remove()) + RARCH_ERR("[Qt]: Thumbnail download finished, but old file could not be deleted.\n"); + else + { + if (m_thumbnailDownloadFile.rename(newFileName)) + { + RARCH_LOG("[Qt]: Thumbnail download finished successfully.\n"); + /* reload thumbnail image */ + emit itemChanged(); + } + else + { + RARCH_ERR("[Qt]: Thumbnail download finished, but temp file could not be renamed.\n"); + emit showErrorMessageDeferred(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE)); + } + } + } + else + { + QByteArray errorArray = reply->errorString().toUtf8(); + const char *errorData = errorArray.constData(); + + RARCH_ERR("[Qt]: Thumbnail download ended prematurely: %s\n", errorData); + emit showErrorMessageDeferred(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData); + } + + reply->disconnect(); + reply->close(); + reply->deleteLater(); + + if (!m_pendingThumbnailDownloadTypes.isEmpty()) + emit gotThumbnailDownload(system, title); +} + +void MainWindow::onDownloadThumbnail(QString system, QString title) +{ + downloadThumbnail(system, title); +} + +void MainWindow::onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + int progress = (bytesReceived / (float)bytesTotal) * 100.0f; + + if (!reply) + return; + + m_thumbnailDownloadProgressDialog->setValue(progress); +} + +void MainWindow::onThumbnailDownloadReadyRead() +{ + QNetworkReply *reply = m_thumbnailDownloadReply.data(); + + if (!reply) + return; + + m_thumbnailDownloadFile.write(reply->readAll()); +} + +void MainWindow::downloadThumbnail(QString system, QString title, QUrl url) +{ + QString systemUnderscore = system; + QString urlString; + QNetworkReply *reply = NULL; + QNetworkRequest request; + QByteArray urlArray; + QString downloadType; + settings_t *settings = config_get_ptr(); + const char *urlData = NULL; + + if (!settings || m_pendingThumbnailDownloadTypes.isEmpty()) + return; + + downloadType = m_pendingThumbnailDownloadTypes.takeFirst(); + + systemUnderscore = systemUnderscore.replace(" ", "_"); + + urlString = QString(THUMBNAIL_URL_HEADER) + systemUnderscore + THUMBNAIL_URL_BRANCH + downloadType + "/" + title + THUMBNAIL_URL_FOOTER; + + if (url.isEmpty()) + url = urlString; + + request.setUrl(url); + + urlArray = url.toString().toUtf8(); + urlData = urlArray.constData(); + + if (m_thumbnailDownloadFile.isOpen()) + { + RARCH_ERR("[Qt]: File is already open.\n"); + return; + } + else + { + QString dirString = QString(settings->paths.directory_thumbnails) + "/" + system + "/" + downloadType; + QString fileName = dirString + "/" + title + THUMBNAIL_IMAGE_EXTENSION + PARTIAL_EXTENSION; + QDir dir; + QByteArray fileNameArray = fileName.toUtf8(); + const char *fileNameData = fileNameArray.constData(); + + dir.mkpath(dirString); + + m_thumbnailDownloadFile.setFileName(fileName); + + if (!m_thumbnailDownloadFile.open(QIODevice::WriteOnly)) + { + showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + RARCH_ERR("[Qt]: Could not open file for writing: %s\n", fileNameData); + return; + } + } + + RARCH_LOG("[Qt]: Starting thumbnail download...\n"); + RARCH_LOG("[Qt]: Downloading URL %s\n", urlData); + + request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT); + + m_thumbnailDownloadProgressDialog->setWindowModality(Qt::NonModal); + m_thumbnailDownloadProgressDialog->setMinimumDuration(0); + m_thumbnailDownloadProgressDialog->setRange(0, 100); + m_thumbnailDownloadProgressDialog->setAutoClose(true); + m_thumbnailDownloadProgressDialog->setAutoReset(true); + m_thumbnailDownloadProgressDialog->setValue(0); + m_thumbnailDownloadProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "..."); + m_thumbnailDownloadProgressDialog->setCancelButtonText(tr("Cancel")); + m_thumbnailDownloadProgressDialog->show(); + + m_thumbnailDownloadReply = m_networkManager->get(request); + + reply = m_thumbnailDownloadReply.data(); + reply->setProperty("system", system); + reply->setProperty("title", title); + reply->setProperty("download_type", downloadType); + + /* make sure any previous connection is removed first */ + disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + disconnect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), reply, SLOT(abort())); + connect(m_thumbnailDownloadProgressDialog, SIGNAL(canceled()), m_thumbnailDownloadProgressDialog, SLOT(cancel())); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onThumbnailDownloadNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(sslErrors(const QList&)), this, SLOT(onThumbnailDownloadNetworkSslErrors(const QList&))); + connect(reply, SIGNAL(finished()), this, SLOT(onThumbnailDownloadFinished())); + connect(reply, SIGNAL(readyRead()), this, SLOT(onThumbnailDownloadReadyRead())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onThumbnailDownloadProgress(qint64, qint64))); +} diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 5e0f65693a..78ccdd45f7 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -85,8 +85,6 @@ extern "C" { #endif #define GENERIC_FOLDER_ICON "/xmb/dot-art/png/folder.png" -#define THUMBNAIL_SCREENSHOT "Named_Snaps" -#define THUMBNAIL_TITLE "Named_Titles" #define HIRAGANA_START 0x3041U #define HIRAGANA_END 0x3096U #define KATAKANA_START 0x30A1U @@ -318,6 +316,9 @@ MainWindow::MainWindow(QWidget *parent) : ,m_updateProgressDialog(new QProgressDialog()) ,m_updateFile() ,m_updateReply() + ,m_thumbnailDownloadProgressDialog(new QProgressDialog()) + ,m_thumbnailDownloadReply() + ,m_pendingThumbnailDownloadTypes() { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -338,6 +339,7 @@ MainWindow::MainWindow(QWidget *parent) : qRegisterMetaType >("ThumbnailWidget"); m_updateProgressDialog->cancel(); + m_thumbnailDownloadProgressDialog->cancel(); m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -535,6 +537,9 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_gridLayoutWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); connect(m_gridLayoutWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onFileDropWidgetContextMenuRequested(const QPoint&))); + connect(this, SIGNAL(itemChanged()), this, SLOT(onItemChanged())); + connect(this, SIGNAL(gotThumbnailDownload(QString,QString)), this, SLOT(onDownloadThumbnail(QString,QString))); + /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ connect(this, SIGNAL(gotLogMessage(const QString&)), this, SLOT(onGotLogMessage(const QString&)), Qt::AutoConnection); connect(this, SIGNAL(gotStatusMessage(QString,unsigned,unsigned,bool)), this, SLOT(onGotStatusMessage(QString,unsigned,unsigned,bool)), Qt::AutoConnection); @@ -581,6 +586,29 @@ MainWindow::~MainWindow() removeGridItems(); } +void MainWindow::onItemChanged() +{ + ViewType viewType = getCurrentViewType(); + + currentItemChanged(getCurrentContentHash()); + + if (viewType == VIEW_TYPE_ICONS) + { + int i; + + for (i = 0; i < m_gridItems.count(); i++) + { + const QPointer &item = m_gridItems.at(i); + + if (item->widget == m_currentGridWidget) + { + loadImageDeferred(item.data(), m_currentGridWidget->property("image_path").toString()); + break; + } + } + } +} + QString MainWindow::getSpecialPlaylistPath(SpecialPlaylist playlist) { switch (playlist) diff --git a/ui/drivers/qt/updateretroarch.cpp b/ui/drivers/qt/updateretroarch.cpp index da67edb862..454de2eb7c 100644 --- a/ui/drivers/qt/updateretroarch.cpp +++ b/ui/drivers/qt/updateretroarch.cpp @@ -338,6 +338,7 @@ void MainWindow::updateRetroArchNightly() m_updateProgressDialog->show(); m_updateReply = m_networkManager->get(request); + reply = m_updateReply.data(); /* make sure any previous connection is removed first */ diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index f3703a499d..69d8b899eb 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -48,6 +48,8 @@ extern "C" { #define ALL_PLAYLISTS_TOKEN "|||ALL|||" #define ICON_PATH "/xmb/dot-art/png/" #define THUMBNAIL_BOXART "Named_Boxarts" +#define THUMBNAIL_SCREENSHOT "Named_Snaps" +#define THUMBNAIL_TITLE "Named_Titles" class QApplication; class QCloseEvent; @@ -295,6 +297,8 @@ signals: void showErrorMessageDeferred(QString msg); void showInfoMessageDeferred(QString msg); void extractArchiveDeferred(QString path); + void itemChanged(); + void gotThumbnailDownload(QString system, QString title); public slots: void onBrowserDownloadsClicked(); @@ -333,6 +337,7 @@ public slots: void updateRetroArchNightly(); void onUpdateRetroArchFinished(bool success); void deferReloadShaderParams(); + void downloadThumbnail(QString system, QString title, QUrl url = QUrl()); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -374,6 +379,14 @@ private slots: void onShowErrorMessage(QString msg); void onShowInfoMessage(QString msg); void onContributorsClicked(); + void onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code); + void onThumbnailDownloadNetworkSslErrors(const QList &errors); + void onThumbnailDownloadFinished(); + void onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onThumbnailDownloadReadyRead(); + void onThumbnailDownloadCanceled(); + void onItemChanged(); + void onDownloadThumbnail(QString system, QString title); int onExtractArchive(QString path); private: @@ -452,6 +465,10 @@ private: QProgressDialog *m_updateProgressDialog; QFile m_updateFile; QPointer m_updateReply; + QProgressDialog *m_thumbnailDownloadProgressDialog; + QFile m_thumbnailDownloadFile; + QPointer m_thumbnailDownloadReply; + QStringList m_pendingThumbnailDownloadTypes; protected: void closeEvent(QCloseEvent *event);