Merge pull request #7049 from bparker06/wimp_update

Qt: add option to update RetroArch (Windows only for now)
This commit is contained in:
Twinaphex 2018-08-07 03:10:32 +02:00 committed by GitHub
commit d4ab18c188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 427 additions and 16 deletions

View File

@ -16,10 +16,11 @@
- LOCALIZATION: Update Spanish translation.
- MIDI: Add MIDI support to the libretro API. Dosbox is the first proof of concept core implementing libretro MIDI.
- MIDI: Add a Windows driver for MIDI, based on winmm.
- MENU/QT/WIMP: QT QSlider styling for Dark Theme.
- MENU/QT/WIMP: Qt QSlider styling for Dark Theme.
- MENU/QT/WIMP: Remove button ghostly inside highlighting.
- MENU/QT/WIMP: Initial grid view.
- MENU/QT/WIMP: Drag&drop to add new playlist items, add option to add/edit/delete playlists.
- MENU/QT/WIMP: Add menu option to update RetroArch (Windows only for now).
- METAL: Initial work-in-progress video driver for Metal. macOS-only right now, and currently requires macOS 10.13.
- METAL: Supports XMB/MaterialUI, has a menu display driver. Has a font rendering driver.
- METAL/SLANG: Slang shaders should be compatible with Metal video driver.

View File

@ -345,9 +345,9 @@ MOC_HEADERS += ui/drivers/ui_qt.h \
ui/drivers/qt/ui_qt_load_core_window.h \
ui/drivers/qt/flowlayout.h
DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) -DHAVE_MAIN
DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) $(QT5NETWORK_CFLAGS) -DHAVE_MAIN
#DEFINES += $(QT5WEBENGINE_CFLAGS)
LIBS += $(QT5CORE_LIBS) $(QT5GUI_LIBS) $(QT5WIDGETS_LIBS) $(QT5CONCURRENT_LIBS)
LIBS += $(QT5CORE_LIBS) $(QT5GUI_LIBS) $(QT5WIDGETS_LIBS) $(QT5CONCURRENT_LIBS) $(QT5NETWORK_LIBS)
#LIBS += $(QT5WEBENGINE_LIBS)
NEED_CXX_LINKER = 1

View File

@ -3488,6 +3488,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM,
"カスタム...")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE,
"設定")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS,
"ツール(&T)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP,
"ヘルプ(&H)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT,
@ -3534,6 +3536,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_WARNING,
"警告")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ERROR,
"エラー")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR,
"ネットワークエラー")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT,
"変更はRetroArchを再起動した後に反映されます。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOG,
@ -3564,6 +3568,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY,
"ファイルは空きです。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED,
"ファイルを読み込みのために開けません。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED,
"ファイルを書き込みのために開けません。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST,
"ファイルは存在しません。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST,
@ -3656,6 +3662,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION,
"質問")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE,
"ファイル削除に失敗しました。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE,
"ファイルの名前変更に失敗しました。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES,
"ファイルの一覧を構築しています...")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST,
@ -3696,3 +3704,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY,
"プレイリストエントリーを更新するに失敗しました。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS,
"必須フィールドがすべて入力されていることを確認してください。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY,
"RetroArchをアップデート (nightly)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED,
"更新に成功しました。変更を適用にするには、RetroArchを再起動する必要があります。")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED,
"更新に失敗しました。")

View File

@ -3764,6 +3764,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM,
"Custom...")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE,
"Options")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS,
"&Tools")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP,
"&Help")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT,
@ -3810,6 +3812,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_WARNING,
"Warning")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ERROR,
"Error")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR,
"Network Error")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT,
"Please restart the program for the changes to take effect.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOG,
@ -3848,6 +3852,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY,
"File is empty.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED,
"Could not open file for reading.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED,
"Could not open file for writing.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST,
"File does not exist.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST,
@ -4186,6 +4192,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION,
"Question")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE,
"Could not delete file.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE,
"Could not rename file.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES,
"Gathering list of files...")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST,
@ -4226,3 +4234,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY,
"Error updating playlist entry.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS,
"Please fill out all required fields.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY,
"Update RetroArch (nightly)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED,
"RetroArch updated successfully. Please restart the application for the changes to take effect.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED,
"Update failed.")

View File

@ -1898,6 +1898,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES,
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT,
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT,
MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS,
MENU_ENUM_LABEL_VALUE_QT_MENU_HELP,
MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER,
MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART,
@ -1934,6 +1935,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK,
MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY,
MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED,
MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED,
MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST,
MENU_ENUM_LABEL_VALUE_QT_ZOOM,
MENU_ENUM_LABEL_VALUE_QT_VIEW,
@ -1947,6 +1949,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM,
MENU_ENUM_LABEL_VALUE_QT_QUESTION,
MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE,
MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE,
MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES,
MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY,
@ -1968,6 +1971,10 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS,
MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT,
MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION,
MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR,
MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY,
MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED,
MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED,
MENU_LABEL(MIDI_INPUT),
MENU_LABEL(MIDI_OUTPUT),
@ -2045,6 +2052,7 @@ enum msg_hash_enums
MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS,
MSG_CHEAT_SEARCH_ADD_MATCH_FAIL,
MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS,
MSG_LAST
};

View File

@ -279,15 +279,17 @@ if [ "$HAVE_QT" != 'no' ] && [ "$MOC_PATH" != 'none' ]; then
check_pkgconf QT5GUI Qt5Gui 5.2
check_pkgconf QT5WIDGETS Qt5Widgets 5.2
check_pkgconf QT5CONCURRENT Qt5Concurrent 5.2
check_pkgconf QT5NETWORK Qt5Network 5.2
#check_pkgconf QT5WEBENGINE Qt5WebEngine 5.4
check_val '' QT5CORE -lQt5Core QT5CORE
check_val '' QT5GUI -lQt5Gui QT5GUI
check_val '' QT5WIDGETS -lQt5Widgets QT5WIDGETS
check_val '' QT5CONCURRENT -lQt5Widgets QT5CONCURRENT
check_val '' QT5CONCURRENT -lQt5Concurrent QT5CONCURRENT
check_val '' QT5NETWORK -lQt5Network QT5NETWORK
#check_val '' QT5WEBENGINE -lQt5WebEngine QT5WEBENGINE
if [ "$HAVE_QT5CORE" = "no" ] || [ "$HAVE_QT5GUI" = "no" ] || [ "$HAVE_QT5WIDGETS" = "no" ] || [ "$HAVE_QT5CONCURRENT" = "no" ]; then
if [ "$HAVE_QT5CORE" = "no" ] || [ "$HAVE_QT5GUI" = "no" ] || [ "$HAVE_QT5WIDGETS" = "no" ] || [ "$HAVE_QT5CONCURRENT" = "no" ] || [ "$HAVE_QT5NETWORK" = "no" ]; then
die : 'Notice: Not building Qt support, required libraries were not found.'
HAVE_QT=no
else

View File

@ -35,6 +35,7 @@
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QtConcurrentRun>
#include <QtNetwork>
#include "../ui_qt.h"
#include "ui_qt_load_core_window.h"
@ -56,10 +57,12 @@ extern "C" {
#include "../../../content.h"
#include "../../../menu/menu_driver.h"
#include "../../../tasks/tasks_internal.h"
#include "../../../config.def.h"
#include <string/stdstring.h>
#include <encodings/utf.h>
#include <file/file_path.h>
#include <file/archive_file.h>
#include <streams/file_stream.h>
#include <math.h>
}
@ -81,6 +84,10 @@ extern "C" {
#define KATAKANA_START 0x30A1U
#define KATAKANA_END 0x30F6U
#define HIRA_KATA_OFFSET (KATAKANA_START - HIRAGANA_START)
#define USER_AGENT "RetroArch-WIMP/1.0"
#define DOCS_URL "http://docs.libretro.com/"
#define PARTIAL_EXTENSION ".partial"
#define TEMP_EXTENSION ".update_tmp"
static ui_window_qt_t ui_window = {0};
@ -908,6 +915,10 @@ MainWindow::MainWindow(QWidget *parent) :
,m_allPlaylistsGridMaxCount(0)
,m_playlistEntryDialog(NULL)
,m_statusMessageElapsedTimer()
,m_networkManager(new QNetworkAccessManager(this))
,m_updateProgressDialog(new QProgressDialog())
,m_updateFile()
,m_updateReply()
{
settings_t *settings = config_get_ptr();
QDir playlistDir(settings->paths.directory_playlist);
@ -927,6 +938,8 @@ MainWindow::MainWindow(QWidget *parent) :
qRegisterMetaType<QPointer<ThumbnailWidget> >("ThumbnailWidget");
m_updateProgressDialog->cancel();
m_gridProgressWidget = new QWidget();
gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget);
@ -1146,6 +1159,8 @@ MainWindow::MainWindow(QWidget *parent) :
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
resizeDocks(QList<QDockWidget*>() << m_searchDock, QList<int>() << 1, Qt::Vertical);
#endif
removeUpdateTempFiles();
}
MainWindow::~MainWindow()
@ -1160,6 +1175,31 @@ MainWindow::~MainWindow()
removeGridItems();
}
void MainWindow::removeUpdateTempFiles()
{
/* a QDir with no path means the current working directory */
QDir dir;
QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name);
int i;
for (i = 0; i < dirList.count(); i++)
{
QString path(dir.path() + "/" + dirList.at(i));
QFile file(path);
if (path.endsWith(TEMP_EXTENSION))
{
QByteArray pathArray = path.toUtf8();
const char *pathData = pathArray.constData();
if (file.remove())
RARCH_LOG("[Qt]: removed temporary update file %s\n", pathData);
else
RARCH_LOG("[Qt]: could not remove temporary update file %s\n", pathData);
}
}
}
void MainWindow::onPlaylistFilesDropped(QStringList files)
{
addFilesToPlaylist(files);
@ -1215,7 +1255,7 @@ void MainWindow::addFilesToPlaylist(QStringList files)
if (currentPlaylistPath == ALL_PLAYLISTS_TOKEN)
{
ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
return;
}
@ -1239,7 +1279,7 @@ void MainWindow::addFilesToPlaylist(QStringList files)
if (selectedName.isEmpty() || selectedPath.isEmpty() ||
selectedDatabase.isEmpty())
{
ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
return;
}
@ -1269,7 +1309,7 @@ void MainWindow::addFilesToPlaylist(QStringList files)
else if (files.count() == 1)
{
/* If adding a single file, tell user that it doesn't exist. */
ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
return;
}
}
@ -1469,11 +1509,11 @@ void MainWindow::showWelcomeScreen()
"Documentation for RetroArch, libretro and cores:<br>\n"
"<a href=\"https://docs.libretro.com/\">https://docs.libretro.com/</a>");
if (!ui_window.qtWindow->settings()->value("show_welcome_screen", true).toBool())
if (!m_settings->value("show_welcome_screen", true).toBool())
return;
if (!ui_window.qtWindow->showMessageBox(welcomeText, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal))
ui_window.qtWindow->settings()->setValue("show_welcome_screen", false);
if (!showMessageBox(welcomeText, MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal))
m_settings->setValue("show_welcome_screen", false);
}
@ -1784,7 +1824,7 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos)
if (!updateCurrentPlaylistEntry(contentHash))
{
ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
return;
}
}
@ -1966,12 +2006,12 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
{
if (currentPlaylistFile.exists())
{
if (ui_window.qtWindow->showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST)).arg(selectedItem->text()), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false))
if (showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST)).arg(selectedItem->text()), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false))
{
if (currentPlaylistFile.remove())
reloadPlaylists();
else
ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
}
}
}
@ -2823,7 +2863,7 @@ void MainWindow::deleteCurrentPlaylistItem()
if (!ok)
return;
if (!ui_window.qtWindow->showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM)).arg(contentHash["label"]), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false))
if (!showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM)).arg(contentHash["label"]), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false))
return;
playlist = playlist_init(playlistData, COLLECTION_SIZE);
@ -4587,7 +4627,313 @@ void MainWindow::showAbout()
void MainWindow::showDocs()
{
QDesktopServices::openUrl(QUrl("http://docs.libretro.com/"));
QDesktopServices::openUrl(QUrl(DOCS_URL));
}
void MainWindow::onUpdateNetworkError(QNetworkReply::NetworkError code)
{
QNetworkReply *reply = m_updateReply.data();
QByteArray errorStringArray;
const char *errorStringData = NULL;
m_updateProgressDialog->reset();
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::onUpdateNetworkSslErrors(const QList<QSslError> &errors)
{
QNetworkReply *reply = m_updateReply.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::onUpdateDownloadCanceled()
{
m_updateProgressDialog->reset();
}
void MainWindow::onRetroArchUpdateDownloadFinished()
{
QNetworkReply *reply = m_updateReply.data();
QNetworkReply::NetworkError error;
int code;
m_updateProgressDialog->reset();
if (!reply)
return;
error = reply->error();
code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (m_updateFile.isOpen())
m_updateFile.close();
if (code != 200)
{
showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": HTTP Code " + QString::number(code), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
RARCH_ERR("[Qt]: RetroArch update failed with HTTP status code: %d\n", code);
reply->disconnect();
reply->abort();
reply->deleteLater();
return;
}
if (error == QNetworkReply::NoError)
{
int index = m_updateFile.fileName().lastIndexOf(PARTIAL_EXTENSION);
QString newFileName = m_updateFile.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]: RetroArch update finished, but old file could not be deleted.\n");
else
{
if (!m_updateFile.rename(newFileName))
RARCH_ERR("[Qt]: RetroArch update finished, but temp file could not be renamed.\n");
else
{
RARCH_LOG("[Qt]: RetroArch update finished downloading successfully.\n");
extractArchive(newFileName);
}
}
}
else
{
QByteArray errorArray = reply->errorString().toUtf8();
const char *errorData = errorArray.constData();
RARCH_ERR("[Qt]: RetroArch update ended prematurely: %s\n", errorData);
showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR)) + ": Code " + QString::number(code) + ": " + errorData, MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
}
reply->disconnect();
reply->close();
reply->deleteLater();
}
static void extractCB(void *task_data, void *user_data, const char *err)
{
decompress_task_data_t *dec = (decompress_task_data_t*)task_data;
MainWindow *mainwindow = (MainWindow*)user_data;
if (err)
RARCH_ERR("%s", err);
if (dec)
{
if (filestream_exists(dec->source_file))
filestream_delete(dec->source_file);
free(dec->source_file);
free(dec);
}
mainwindow->onUpdateRetroArchFinished(string_is_empty(err));
}
void MainWindow::onUpdateRetroArchFinished(bool success)
{
m_updateProgressDialog->reset();
if (!success)
{
RARCH_ERR("[Qt]: RetroArch update failed.\n");
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
return;
}
RARCH_LOG("[Qt]: RetroArch update finished successfully.\n");
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED), MainWindow::MSGBOX_TYPE_INFO, Qt::ApplicationModal, false);
}
int MainWindow::extractArchive(QString path)
{
QByteArray pathArray = path.toUtf8();
const char *file = pathArray.constData();
file_archive_transfer_t state;
struct archive_extract_userdata userdata;
struct string_list *file_list = file_archive_get_file_list(file, NULL);
bool returnerr = true;
unsigned i;
if (!file_list || file_list->size == 0)
{
showMessageBox("Error: Archive is empty.", MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
RARCH_ERR("[Qt]: Downloaded archive is empty?\n");
return -1;
}
for (i = 0; i < file_list->size; i++)
{
QFile fileObj(file_list->elems[i].data);
if (fileObj.exists())
{
if (!fileObj.remove())
{
/* if we cannot delete the existing file to update it, rename it for now and delete later */
QFile fileTemp(fileObj.fileName() + TEMP_EXTENSION);
if (fileTemp.exists())
{
if (!fileTemp.remove())
{
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
RARCH_ERR("[Qt]: Could not delete file: %s\n", file_list->elems[i].data);
return -1;
}
}
if (!fileObj.rename(fileTemp.fileName()))
{
showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false);
RARCH_ERR("[Qt]: Could not rename file: %s\n", file_list->elems[i].data);
return -1;
}
}
}
}
string_list_free(file_list);
memset(&state, 0, sizeof(state));
memset(&userdata, 0, sizeof(userdata));
state.type = ARCHIVE_TRANSFER_INIT;
m_updateProgressDialog->setWindowModality(Qt::NonModal);
m_updateProgressDialog->setMinimumDuration(0);
m_updateProgressDialog->setRange(0, 0);
m_updateProgressDialog->setAutoClose(true);
m_updateProgressDialog->setAutoReset(true);
m_updateProgressDialog->setValue(0);
m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_EXTRACTING)) + "...");
m_updateProgressDialog->setCancelButtonText(QString());
m_updateProgressDialog->show();
if (!task_push_decompress(file, ".",
NULL, NULL, NULL,
extractCB, this))
{
m_updateProgressDialog->reset();
return -1;
}
return returnerr;
}
void MainWindow::onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
QNetworkReply *reply = m_updateReply.data();
int progress = (bytesReceived / (float)bytesTotal) * 100.0f;
if (!reply)
return;
m_updateProgressDialog->setValue(progress);
}
void MainWindow::onUpdateDownloadReadyRead()
{
QNetworkReply *reply = m_updateReply.data();
if (!reply)
return;
m_updateFile.write(reply->readAll());
}
void MainWindow::updateRetroArchNightly()
{
QUrl url(QUrl(buildbot_server_url).resolved(QUrl("../RetroArch_update.zip")));
QNetworkRequest request(url);
QNetworkReply *reply = NULL;
QByteArray urlArray = url.toString().toUtf8();
const char *urlData = urlArray.constData();
if (m_updateFile.isOpen())
{
RARCH_ERR("[Qt]: File is already open.\n");
return;
}
else
{
QString fileName = QFileInfo(url.toString()).fileName() + PARTIAL_EXTENSION;
QByteArray fileNameArray = fileName.toUtf8();
const char *fileNameData = fileNameArray.constData();
m_updateFile.setFileName(fileName);
if (!m_updateFile.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 update of RetroArch...\n");
RARCH_LOG("[Qt]: Downloading URL %s\n", urlData);
request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT);
m_updateProgressDialog->setWindowModality(Qt::NonModal);
m_updateProgressDialog->setMinimumDuration(0);
m_updateProgressDialog->setRange(0, 100);
m_updateProgressDialog->setAutoClose(true);
m_updateProgressDialog->setAutoReset(true);
m_updateProgressDialog->setValue(0);
m_updateProgressDialog->setLabelText(QString(msg_hash_to_str(MSG_DOWNLOADING)) + "...");
m_updateProgressDialog->setCancelButtonText(tr("Cancel"));
m_updateProgressDialog->show();
m_updateReply = m_networkManager->get(request);
reply = m_updateReply.data();
/* make sure any previous connection is removed first */
disconnect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort()));
disconnect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(reset()));
connect(m_updateProgressDialog, SIGNAL(canceled()), reply, SLOT(abort()));
connect(m_updateProgressDialog, SIGNAL(canceled()), m_updateProgressDialog, SLOT(reset()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onUpdateNetworkError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(onUpdateNetworkSslErrors(const QList<QSslError>&)));
connect(reply, SIGNAL(finished()), this, SLOT(onRetroArchUpdateDownloadFinished()));
connect(reply, SIGNAL(readyRead()), this, SLOT(onUpdateDownloadReadyRead()));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onUpdateDownloadProgress(qint64, qint64)));
}
const QPixmap getInvader()

View File

@ -224,6 +224,8 @@ static void* ui_companion_qt_init(void)
QMenu *editMenu = NULL;
QMenu *viewMenu = NULL;
QMenu *viewClosedDocksMenu = NULL;
QMenu *toolsMenu = NULL;
QMenu *updaterMenu = NULL;
QMenu *helpMenu = NULL;
QRect desktopRect;
QDockWidget *thumbnailDock = NULL;
@ -323,6 +325,11 @@ static void* ui_companion_qt_init(void)
viewMenu->addSeparator();
viewMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS), mainwindow->viewOptionsDialog(), SLOT(showDialog()));
toolsMenu = menu->addMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS));
updaterMenu = toolsMenu->addMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER));
#ifdef Q_OS_WIN
updaterMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY), mainwindow, SLOT(updateRetroArchNightly()));
#endif
helpMenu = menu->addMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP));
helpMenu->addAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION)), mainwindow, SLOT(showDocs()));
helpMenu->addAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT)) + "...", mainwindow, SLOT(showAbout()));

View File

@ -35,6 +35,8 @@
#include <QPointer>
#include <QProgressBar>
#include <QElapsedTimer>
#include <QSslError>
#include <QNetworkReply>
extern "C" {
#include <retro_assert.h>
@ -67,6 +69,9 @@ class QScrollArea;
class QSlider;
class QDragEnterEvent;
class QDropEvent;
class QNetworkAccessManager;
class QNetworkReply;
class QProgressDialog;
class LoadCoreWindow;
class MainWindow;
class ThumbnailWidget;
@ -392,6 +397,8 @@ public slots:
void onFileDropWidgetContextMenuRequested(const QPoint &pos);
void showAbout();
void showDocs();
void updateRetroArchNightly();
void onUpdateRetroArchFinished(bool success);
private slots:
void onLoadCoreClicked(const QStringList &extensionFilters = QStringList());
@ -423,6 +430,12 @@ private slots:
void onGridItemDoubleClicked();
void onGridItemClicked();
void onPlaylistFilesDropped(QStringList files);
void onUpdateNetworkError(QNetworkReply::NetworkError code);
void onUpdateNetworkSslErrors(const QList<QSslError> &errors);
void onRetroArchUpdateDownloadFinished();
void onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void onUpdateDownloadReadyRead();
void onUpdateDownloadCanceled();
private:
void setCurrentCoreLabel();
@ -433,6 +446,8 @@ private:
void loadImageDeferred(GridItem *item, QString path);
void calcGridItemSize(GridItem *item, int zoomValue);
bool updateCurrentPlaylistEntry(const QHash<QString, QString> &contentHash);
int extractArchive(QString path);
void removeUpdateTempFiles();
QVector<QHash<QString, QString> > getPlaylistItems(QString pathString);
LoadCoreWindow *m_loadCoreWindow;
@ -493,6 +508,10 @@ private:
int m_allPlaylistsGridMaxCount;
PlaylistEntryDialog *m_playlistEntryDialog;
QElapsedTimer m_statusMessageElapsedTimer;
QNetworkAccessManager *m_networkManager;
QProgressDialog *m_updateProgressDialog;
QFile m_updateFile;
QPointer<QNetworkReply> m_updateReply;
protected:
void closeEvent(QCloseEvent *event);