mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 00:59:44 -06:00
Unify ISOFile (wx) with GameFile (Qt) and put it in UICommon
The original reason I wanted to do this was so that we can replace the Android-specific code with this in the future, but of course, just deduplicating between DolphinWX and DolphinQt2 is nice too. Fixes: - DolphinQt2 showing the wrong size for split WBFS disc images. - DolphinQt2 being case sensitive when checking if a file is a DOL/ELF. - DolphinQt2 not detecting when a Wii banner has become available after the game list cache was created. Removes: - DolphinWX's ability to load PNGs as custom banners. But it was already rather broken (see https://bugs.dolphin-emu.org/issues/10365 and https://bugs.dolphin-emu.org/issues/10366). The reason I removed this was because PNG decoding relied on wx code and we don't have any good non-wx/Qt code for loading PNG files right now (let's not use SOIL), but we should be able to use libpng directly to implement PNG loading in the future. - DolphinQt2's ability to ignore a cached game if the last modified time differs. We currently don't have a non-wx/Qt way to get the time.
This commit is contained in:
@ -82,8 +82,6 @@ set(SRCS
|
||||
Debugger/RegisterColumn.cpp
|
||||
Debugger/RegisterWidget.cpp
|
||||
Debugger/WatchWidget.cpp
|
||||
GameList/GameFileCache.cpp
|
||||
GameList/GameFile.cpp
|
||||
GameList/GameList.cpp
|
||||
GameList/GameListModel.cpp
|
||||
GameList/GameTracker.cpp
|
||||
@ -98,6 +96,7 @@ set(SRCS
|
||||
NetPlay/PadMappingDialog.cpp
|
||||
QtUtils/DoubleClickEventFilter.cpp
|
||||
QtUtils/ElidedButton.cpp
|
||||
QtUtils/ImageConverter.cpp
|
||||
QtUtils/ListTabWidget.cpp
|
||||
QtUtils/WindowActivationEventFilter.cpp
|
||||
QtUtils/AspectRatioWidget.cpp
|
||||
|
@ -16,10 +16,10 @@
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinQt2/Config/CheatCodeEditor.h"
|
||||
#include "DolphinQt2/Config/CheatWarningWidget.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
ARCodeWidget::ARCodeWidget(const GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID().toStdString()), m_game_revision(game.GetRevision())
|
||||
ARCodeWidget::ARCodeWidget(const UICommon::GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID()), m_game_revision(game.GetRevision())
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
@ -12,8 +12,12 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
|
||||
class CheatWarningWidget;
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class CheatWarningWidget;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
@ -23,7 +27,7 @@ class ARCodeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ARCodeWidget(const GameFile& game);
|
||||
explicit ARCodeWidget(const UICommon::GameFile& game);
|
||||
|
||||
signals:
|
||||
void OpenGeneralSettings();
|
||||
@ -41,7 +45,7 @@ private:
|
||||
void OnCodeEditPressed();
|
||||
void OnCodeRemovePressed();
|
||||
|
||||
const GameFile& m_game;
|
||||
const UICommon::GameFile& m_game;
|
||||
std::string m_game_id;
|
||||
u16 m_game_revision;
|
||||
|
||||
|
@ -37,8 +37,8 @@ enum class EntryType
|
||||
};
|
||||
Q_DECLARE_METATYPE(EntryType);
|
||||
|
||||
FilesystemWidget::FilesystemWidget(const GameFile& game)
|
||||
: m_game(game), m_volume(DiscIO::CreateVolumeFromFilename(game.GetFilePath().toStdString()))
|
||||
FilesystemWidget::FilesystemWidget(const UICommon::GameFile& game)
|
||||
: m_game(game), m_volume(DiscIO::CreateVolumeFromFilename(game.GetFilePath()))
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class QStandardItem;
|
||||
class QStandardItemModel;
|
||||
@ -24,7 +24,7 @@ class FilesystemWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FilesystemWidget(const GameFile& game);
|
||||
explicit FilesystemWidget(const UICommon::GameFile& game);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
@ -46,6 +46,6 @@ private:
|
||||
QStandardItemModel* m_tree_model;
|
||||
QTreeView* m_tree_view;
|
||||
|
||||
GameFile m_game;
|
||||
UICommon::GameFile m_game;
|
||||
std::unique_ptr<DiscIO::Volume> m_volume;
|
||||
};
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "Core/ConfigLoaders/GameConfigLoader.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinQt2/Config/Graphics/GraphicsSlider.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
constexpr int DETERMINISM_NOT_SET_INDEX = 0;
|
||||
constexpr int DETERMINISM_AUTO_INDEX = 1;
|
||||
@ -35,9 +35,9 @@ constexpr const char* DETERMINISM_AUTO_STRING = "auto";
|
||||
constexpr const char* DETERMINISM_NONE_STRING = "none";
|
||||
constexpr const char* DETERMINISM_FAKE_COMPLETION_STRING = "fake-completion";
|
||||
|
||||
GameConfigWidget::GameConfigWidget(const GameFile& game) : m_game(game)
|
||||
GameConfigWidget::GameConfigWidget(const UICommon::GameFile& game) : m_game(game)
|
||||
{
|
||||
m_game_id = m_game.GetGameID().toStdString();
|
||||
m_game_id = m_game.GetGameID();
|
||||
m_gameini_local_path =
|
||||
QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");
|
||||
m_gameini_local = SConfig::LoadLocalGameIni(m_game_id, m_game.GetRevision());
|
||||
@ -241,8 +241,8 @@ void GameConfigWidget::SaveCheckBox(QCheckBox* checkbox, const std::string& sect
|
||||
void GameConfigWidget::LoadSettings()
|
||||
{
|
||||
// Load state information
|
||||
m_state_combo->setCurrentIndex(m_game.GetRating());
|
||||
m_state_comment_edit->setText(m_game.GetIssues());
|
||||
m_state_combo->setCurrentIndex(m_game.GetEmuState());
|
||||
m_state_comment_edit->setText(QString::fromStdString(m_game.GetIssues()));
|
||||
|
||||
// Load game-specific settings
|
||||
|
||||
@ -301,10 +301,10 @@ void GameConfigWidget::SaveSettings()
|
||||
QString comment = m_state_comment_edit->text();
|
||||
int state = m_state_combo->currentIndex();
|
||||
|
||||
if (comment != m_game.GetIssues())
|
||||
if (comment != QString::fromStdString(m_game.GetIssues()))
|
||||
m_gameini_local.GetOrCreateSection("EmuState")->Set("EmulationIssues", comment.toStdString());
|
||||
|
||||
if (state != m_game.GetRating())
|
||||
if (state != m_game.GetEmuState())
|
||||
m_gameini_local.GetOrCreateSection("EmuState")->Set("EmulationStateId", state);
|
||||
|
||||
// Save game-specific settings
|
||||
|
@ -11,7 +11,11 @@
|
||||
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QGroupBox;
|
||||
@ -25,7 +29,7 @@ class GameConfigWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GameConfigWidget(const GameFile& game);
|
||||
explicit GameConfigWidget(const UICommon::GameFile& game);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
@ -65,6 +69,6 @@ private:
|
||||
IniFile m_gameini_local;
|
||||
IniFile m_gameini_default;
|
||||
|
||||
const GameFile& m_game;
|
||||
const UICommon::GameFile& m_game;
|
||||
std::string m_game_id;
|
||||
};
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "DolphinQt2/Config/CheatCodeEditor.h"
|
||||
#include "DolphinQt2/Config/CheatWarningWidget.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
GeckoCodeWidget::GeckoCodeWidget(const GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID().toStdString()), m_game_revision(game.GetRevision())
|
||||
GeckoCodeWidget::GeckoCodeWidget(const UICommon::GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID()), m_game_revision(game.GetRevision())
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
@ -13,18 +13,22 @@
|
||||
#include "Core/GeckoCode.h"
|
||||
|
||||
class CheatWarningWidget;
|
||||
class GameFile;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QTextEdit;
|
||||
class QPushButton;
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class GeckoCodeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GeckoCodeWidget(const GameFile& game);
|
||||
explicit GeckoCodeWidget(const UICommon::GameFile& game);
|
||||
|
||||
signals:
|
||||
void OpenGeneralSettings();
|
||||
@ -43,7 +47,7 @@ private:
|
||||
void DownloadCodes();
|
||||
void SaveCodes();
|
||||
|
||||
const GameFile& m_game;
|
||||
const UICommon::GameFile& m_game;
|
||||
std::string m_game_id;
|
||||
u16 m_game_revision;
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DolphinQt2/Config/InfoWidget.h"
|
||||
#include "DolphinQt2/QtUtils/ImageConverter.h"
|
||||
#include "UICommon/UICommon.h"
|
||||
|
||||
InfoWidget::InfoWidget(const GameFile& game) : m_game(game)
|
||||
InfoWidget::InfoWidget(const UICommon::GameFile& game) : m_game(game)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->addWidget(CreateISODetails());
|
||||
@ -32,17 +34,19 @@ QGroupBox* InfoWidget::CreateISODetails()
|
||||
|
||||
QLineEdit* file_path = CreateValueDisplay(m_game.GetFilePath());
|
||||
QLineEdit* internal_name = CreateValueDisplay(m_game.GetInternalName());
|
||||
QString game_id_string = m_game.GetGameID();
|
||||
|
||||
QString game_id_string = QString::fromStdString(m_game.GetGameID());
|
||||
if (const u64 title_id = m_game.GetTitleID())
|
||||
game_id_string += QStringLiteral(" (%1)").arg(title_id, 16, 16, QLatin1Char('0'));
|
||||
QLineEdit* game_id = CreateValueDisplay(game_id_string);
|
||||
QLineEdit* country = CreateValueDisplay(m_game.GetCountry());
|
||||
|
||||
QLineEdit* country = CreateValueDisplay(DiscIO::GetName(m_game.GetCountry(), true));
|
||||
QLineEdit* maker = CreateValueDisplay(m_game.GetMaker());
|
||||
QLineEdit* maker_id = CreateValueDisplay(QStringLiteral("0x") + m_game.GetMakerID());
|
||||
QLineEdit* maker_id = CreateValueDisplay("0x" + m_game.GetMakerID());
|
||||
QLineEdit* disc_number = CreateValueDisplay(QString::number(m_game.GetDiscNumber()));
|
||||
QLineEdit* revision = CreateValueDisplay(QString::number(m_game.GetRevision()));
|
||||
QLineEdit* apploader_date = CreateValueDisplay(m_game.GetApploaderDate());
|
||||
QLineEdit* iso_size = CreateValueDisplay(FormatSize(m_game.GetFileSize()));
|
||||
QLineEdit* iso_size = CreateValueDisplay(UICommon::FormatSize(m_game.GetFileSize()));
|
||||
QWidget* checksum = CreateChecksumComputer();
|
||||
|
||||
layout->addRow(tr("File Path:"), file_path);
|
||||
@ -75,7 +79,7 @@ QGroupBox* InfoWidget::CreateBannerDetails()
|
||||
CreateLanguageSelector();
|
||||
|
||||
layout->addRow(tr("Show Language:"), m_language_selector);
|
||||
if (m_game.GetPlatformID() == DiscIO::Platform::GAMECUBE_DISC)
|
||||
if (m_game.GetPlatform() == DiscIO::Platform::GAMECUBE_DISC)
|
||||
{
|
||||
layout->addRow(tr("Short Name:"), m_short_name);
|
||||
layout->addRow(tr("Short Maker:"), m_short_maker);
|
||||
@ -83,27 +87,26 @@ QGroupBox* InfoWidget::CreateBannerDetails()
|
||||
layout->addRow(tr("Long Maker:"), m_long_maker);
|
||||
layout->addRow(tr("Description:"), m_description);
|
||||
}
|
||||
else if (DiscIO::IsWii(m_game.GetPlatformID()))
|
||||
else if (DiscIO::IsWii(m_game.GetPlatform()))
|
||||
{
|
||||
layout->addRow(tr("Name:"), m_long_name);
|
||||
}
|
||||
|
||||
if (!m_game.GetBanner().isNull())
|
||||
{
|
||||
layout->addRow(tr("Banner:"), CreateBannerGraphic());
|
||||
}
|
||||
QPixmap banner = ToQPixmap(m_game.GetBannerImage());
|
||||
if (!banner.isNull())
|
||||
layout->addRow(tr("Banner:"), CreateBannerGraphic(banner));
|
||||
|
||||
group->setLayout(layout);
|
||||
return group;
|
||||
}
|
||||
|
||||
QWidget* InfoWidget::CreateBannerGraphic()
|
||||
QWidget* InfoWidget::CreateBannerGraphic(const QPixmap& image)
|
||||
{
|
||||
QWidget* widget = new QWidget();
|
||||
QHBoxLayout* layout = new QHBoxLayout();
|
||||
|
||||
QLabel* banner = new QLabel();
|
||||
banner->setPixmap(m_game.GetBanner());
|
||||
banner->setPixmap(image);
|
||||
QPushButton* save = new QPushButton(tr("Save as..."));
|
||||
connect(save, &QPushButton::clicked, this, &InfoWidget::SaveBanner);
|
||||
|
||||
@ -117,7 +120,7 @@ void InfoWidget::SaveBanner()
|
||||
{
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(),
|
||||
tr("PNG image file (*.png);; All Files (*)"));
|
||||
m_game.GetBanner().save(path, "PNG");
|
||||
ToQPixmap(m_game.GetBannerImage()).save(path, "PNG");
|
||||
}
|
||||
|
||||
QLineEdit* InfoWidget::CreateValueDisplay(const QString& value)
|
||||
@ -128,14 +131,18 @@ QLineEdit* InfoWidget::CreateValueDisplay(const QString& value)
|
||||
return value_display;
|
||||
}
|
||||
|
||||
QLineEdit* InfoWidget::CreateValueDisplay(const std::string& value)
|
||||
{
|
||||
return CreateValueDisplay(QString::fromStdString(value));
|
||||
}
|
||||
|
||||
void InfoWidget::CreateLanguageSelector()
|
||||
{
|
||||
m_language_selector = new QComboBox();
|
||||
QList<DiscIO::Language> languages = m_game.GetAvailableLanguages();
|
||||
for (int i = 0; i < languages.count(); i++)
|
||||
for (DiscIO::Language language : m_game.GetLanguages())
|
||||
{
|
||||
DiscIO::Language language = languages.at(i);
|
||||
m_language_selector->addItem(m_game.GetLanguage(language), static_cast<int>(language));
|
||||
m_language_selector->addItem(QString::fromStdString(DiscIO::GetName(language, true)),
|
||||
static_cast<int>(language));
|
||||
}
|
||||
if (m_language_selector->count() == 1)
|
||||
m_language_selector->setDisabled(true);
|
||||
@ -149,11 +156,11 @@ void InfoWidget::ChangeLanguage()
|
||||
{
|
||||
DiscIO::Language language =
|
||||
static_cast<DiscIO::Language>(m_language_selector->currentData().toInt());
|
||||
m_short_name->setText(m_game.GetShortName(language));
|
||||
m_short_maker->setText(m_game.GetShortMaker(language));
|
||||
m_long_name->setText(m_game.GetLongName(language));
|
||||
m_long_maker->setText(m_game.GetLongMaker(language));
|
||||
m_description->setText(m_game.GetDescription(language));
|
||||
m_short_name->setText(QString::fromStdString(m_game.GetShortName(language)));
|
||||
m_short_maker->setText(QString::fromStdString(m_game.GetShortMaker(language)));
|
||||
m_long_name->setText(QString::fromStdString(m_game.GetLongName(language)));
|
||||
m_long_maker->setText(QString::fromStdString(m_game.GetLongMaker(language)));
|
||||
m_description->setText(QString::fromStdString(m_game.GetDescription(language)));
|
||||
}
|
||||
|
||||
QWidget* InfoWidget::CreateChecksumComputer()
|
||||
@ -176,8 +183,7 @@ void InfoWidget::ComputeChecksum()
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.reset();
|
||||
std::unique_ptr<DiscIO::BlobReader> file(
|
||||
DiscIO::CreateBlobReader(m_game.GetFilePath().toStdString()));
|
||||
std::unique_ptr<DiscIO::BlobReader> file(DiscIO::CreateBlobReader(m_game.GetFilePath()));
|
||||
std::vector<u8> file_data(8 * 1080 * 1080); // read 1MB at a time
|
||||
u64 game_size = file->GetDataSize();
|
||||
u64 read_offset = 0;
|
||||
|
@ -4,20 +4,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class QComboBox;
|
||||
class QGroupBox;
|
||||
class QTextEdit;
|
||||
class QLineEdit;
|
||||
class QPixmap;
|
||||
class QTextEdit;
|
||||
|
||||
class InfoWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InfoWidget(const GameFile& game);
|
||||
explicit InfoWidget(const UICommon::GameFile& game);
|
||||
|
||||
private:
|
||||
void ComputeChecksum();
|
||||
@ -26,13 +29,13 @@ private:
|
||||
|
||||
QGroupBox* CreateBannerDetails();
|
||||
QGroupBox* CreateISODetails();
|
||||
QLineEdit* CreateValueDisplay() { return CreateValueDisplay(QStringLiteral("")); };
|
||||
QLineEdit* CreateValueDisplay(const QString& value);
|
||||
QLineEdit* CreateValueDisplay(const std::string& value = "");
|
||||
QWidget* CreateChecksumComputer();
|
||||
void CreateLanguageSelector();
|
||||
QWidget* CreateBannerGraphic();
|
||||
QWidget* CreateBannerGraphic(const QPixmap& image);
|
||||
|
||||
GameFile m_game;
|
||||
UICommon::GameFile m_game;
|
||||
QLineEdit* m_checksum_result;
|
||||
QComboBox* m_language_selector;
|
||||
QLineEdit* m_long_name;
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
|
||||
class QDialogButtonBox;
|
||||
class QGroupBox;
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinQt2/Config/NewPatchDialog.h"
|
||||
|
||||
PatchesWidget::PatchesWidget(const GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID().toStdString()), m_game_revision(game.GetRevision())
|
||||
PatchesWidget::PatchesWidget(const UICommon::GameFile& game)
|
||||
: m_game(game), m_game_id(game.GetGameID()), m_game_revision(game.GetRevision())
|
||||
{
|
||||
IniFile game_ini_local;
|
||||
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
@ -19,7 +19,7 @@ class QPushButton;
|
||||
class PatchesWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit PatchesWidget(const GameFile& game);
|
||||
explicit PatchesWidget(const UICommon::GameFile& game);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
@ -39,7 +39,7 @@ private:
|
||||
QPushButton* m_remove_button;
|
||||
|
||||
std::vector<PatchEngine::Patch> m_patches;
|
||||
const GameFile& m_game;
|
||||
const UICommon::GameFile& m_game;
|
||||
std::string m_game_id;
|
||||
u16 m_game_revision;
|
||||
};
|
||||
|
@ -13,11 +13,15 @@
|
||||
#include "DolphinQt2/Config/InfoWidget.h"
|
||||
#include "DolphinQt2/Config/PatchesWidget.h"
|
||||
#include "DolphinQt2/Config/PropertiesDialog.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
PropertiesDialog::PropertiesDialog(QWidget* parent, const GameFile& game) : QDialog(parent)
|
||||
PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& game)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(
|
||||
QStringLiteral("%1: %2 - %3").arg(game.GetFileName(), game.GetGameID(), game.GetLongName()));
|
||||
setWindowTitle(QStringLiteral("%1: %2 - %3")
|
||||
.arg(QString::fromStdString(game.GetFileName()),
|
||||
QString::fromStdString(game.GetGameID()),
|
||||
QString::fromStdString(game.GetLongName())));
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
|
||||
QTabWidget* tab_widget = new QTabWidget(this);
|
||||
@ -39,7 +43,7 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const GameFile& game) : QDia
|
||||
tab_widget->addTab(gecko, tr("Gecko Codes"));
|
||||
tab_widget->addTab(info, tr("Info"));
|
||||
|
||||
if (DiscIO::IsDisc(game.GetPlatformID()))
|
||||
if (DiscIO::IsDisc(game.GetPlatform()))
|
||||
{
|
||||
FilesystemWidget* filesystem = new FilesystemWidget(game);
|
||||
tab_widget->addTab(filesystem, tr("Filesystem"));
|
||||
|
@ -6,13 +6,16 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class PropertiesDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropertiesDialog(QWidget* parent, const GameFile& game);
|
||||
explicit PropertiesDialog(QWidget* parent, const UICommon::GameFile& game);
|
||||
|
||||
signals:
|
||||
void OpenGeneralSettings();
|
||||
|
@ -97,7 +97,6 @@
|
||||
<QtMoc Include="Debugger\NewBreakpointDialog.h" />
|
||||
<QtMoc Include="Debugger\RegisterWidget.h" />
|
||||
<QtMoc Include="Debugger\WatchWidget.h" />
|
||||
<QtMoc Include="GameList\GameFile.h" />
|
||||
<QtMoc Include="GameList\GameList.h" />
|
||||
<QtMoc Include="GameList\GameListModel.h" />
|
||||
<QtMoc Include="GameList\GameTracker.h" />
|
||||
@ -250,8 +249,6 @@
|
||||
<ClCompile Include="Debugger\RegisterWidget.cpp" />
|
||||
<ClCompile Include="Debugger\WatchWidget.cpp" />
|
||||
<ClCompile Include="GCMemcardManager.cpp" />
|
||||
<ClCompile Include="GameList\GameFile.cpp" />
|
||||
<ClCompile Include="GameList\GameFileCache.cpp" />
|
||||
<ClCompile Include="GameList\GameList.cpp" />
|
||||
<ClCompile Include="GameList\GameListModel.cpp" />
|
||||
<ClCompile Include="GameList\GameTracker.cpp" />
|
||||
@ -271,6 +268,7 @@
|
||||
<ClCompile Include="NetPlay\PadMappingDialog.cpp" />
|
||||
<ClCompile Include="QtUtils\DoubleClickEventFilter.cpp" />
|
||||
<ClCompile Include="QtUtils\ElidedButton.cpp" />
|
||||
<ClCompile Include="QtUtils\ImageConverter.cpp" />
|
||||
<ClCompile Include="QtUtils\ListTabWidget.cpp" />
|
||||
<ClCompile Include="QtUtils\WindowActivationEventFilter.cpp" />
|
||||
<ClCompile Include="QtUtils\AspectRatioWidget.cpp" />
|
||||
@ -311,9 +309,9 @@
|
||||
<ClInclude Include="Config\Mapping\WiimoteEmuMotionControl.h" />
|
||||
<ClInclude Include="Config\RegisterColumn.h" />
|
||||
<ClInclude Include="Config\RegisterWidget.h" />
|
||||
<ClInclude Include="GameList\GameFileCache.h" />
|
||||
<ClInclude Include="QtUtils\BlockUserInputFilter.h" />
|
||||
<ClInclude Include="QtUtils\ElidedButton.h" />
|
||||
<ClInclude Include="QtUtils\ImageConverter.h" />
|
||||
<ClInclude Include="QtUtils\ListTabWidget.h" />
|
||||
<ClInclude Include="Resources.h" />
|
||||
<ClInclude Include="Settings\GameCubePane.h" />
|
||||
|
@ -1,481 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/NandPaths.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/WiiSaveCrypted.h"
|
||||
#include "Core/IOS/ES/ES.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/WiiUtils.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/Resources.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
|
||||
QList<DiscIO::Language> GameFile::GetAvailableLanguages() const
|
||||
{
|
||||
return m_long_names.keys();
|
||||
}
|
||||
|
||||
static QMap<DiscIO::Language, QString>
|
||||
ConvertLanguageMap(const std::map<DiscIO::Language, std::string>& map)
|
||||
{
|
||||
QMap<DiscIO::Language, QString> result;
|
||||
for (auto entry : map)
|
||||
result.insert(entry.first, QString::fromStdString(entry.second).trimmed());
|
||||
return result;
|
||||
}
|
||||
|
||||
GameFile::GameFile()
|
||||
{
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
GameFile::GameFile(const QString& path) : m_path(path)
|
||||
{
|
||||
m_valid = false;
|
||||
|
||||
if (!LoadFileInfo(path))
|
||||
return;
|
||||
|
||||
if (TryLoadVolume())
|
||||
{
|
||||
LoadState();
|
||||
}
|
||||
else if (!TryLoadElfDol())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
bool GameFile::IsValid() const
|
||||
{
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
if (m_platform == DiscIO::Platform::WII_WAD && !IOS::ES::IsChannel(m_title_id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameFile::ReadBanner(const DiscIO::Volume& volume)
|
||||
{
|
||||
int width, height;
|
||||
std::vector<u32> buffer = volume.GetBanner(&width, &height);
|
||||
QImage banner(width, height, QImage::Format_RGB888);
|
||||
for (int i = 0; i < width * height; i++)
|
||||
{
|
||||
int x = i % width, y = i / width;
|
||||
banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16, (buffer[i] & 0x00FF00) >> 8,
|
||||
(buffer[i] & 0x0000FF) >> 0));
|
||||
}
|
||||
|
||||
if (!banner.isNull())
|
||||
m_banner = QPixmap::fromImage(banner);
|
||||
}
|
||||
|
||||
bool GameFile::LoadFileInfo(const QString& path)
|
||||
{
|
||||
QFileInfo info(path);
|
||||
if (!info.exists() || !info.isReadable())
|
||||
return false;
|
||||
|
||||
m_last_modified = info.lastModified();
|
||||
m_size = info.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameFile::LoadState()
|
||||
{
|
||||
IniFile ini = SConfig::LoadGameIni(m_game_id.toStdString(), m_revision);
|
||||
std::string issues_temp;
|
||||
ini.GetIfExists("EmuState", "EmulationStateId", &m_rating);
|
||||
ini.GetIfExists("EmuState", "EmulationIssues", &issues_temp);
|
||||
m_issues = QString::fromStdString(issues_temp);
|
||||
}
|
||||
|
||||
bool GameFile::IsElfOrDol()
|
||||
{
|
||||
QString extension = GetFileExtension();
|
||||
return extension == QStringLiteral("elf") || extension == QStringLiteral("dol");
|
||||
}
|
||||
|
||||
bool GameFile::TryLoadVolume()
|
||||
{
|
||||
QSharedPointer<DiscIO::Volume> volume(
|
||||
DiscIO::CreateVolumeFromFilename(m_path.toStdString()).release());
|
||||
if (volume == nullptr)
|
||||
return false;
|
||||
|
||||
m_game_id = QString::fromStdString(volume->GetGameID());
|
||||
std::string maker_id = volume->GetMakerID();
|
||||
m_title_id = volume->GetTitleID().value_or(0);
|
||||
m_maker = QString::fromStdString(DiscIO::GetCompanyFromID(maker_id));
|
||||
m_maker_id = QString::fromStdString(maker_id);
|
||||
m_revision = volume->GetRevision().value_or(0);
|
||||
m_internal_name = QString::fromStdString(volume->GetInternalName());
|
||||
m_short_names = ConvertLanguageMap(volume->GetShortNames());
|
||||
m_long_names = ConvertLanguageMap(volume->GetLongNames());
|
||||
m_short_makers = ConvertLanguageMap(volume->GetShortMakers());
|
||||
m_long_makers = ConvertLanguageMap(volume->GetLongMakers());
|
||||
m_descriptions = ConvertLanguageMap(volume->GetDescriptions());
|
||||
m_disc_number = volume->GetDiscNumber().value_or(0);
|
||||
m_platform = volume->GetVolumeType();
|
||||
m_region = volume->GetRegion();
|
||||
m_country = volume->GetCountry();
|
||||
m_blob_type = volume->GetBlobType();
|
||||
m_raw_size = volume->GetRawSize();
|
||||
m_apploader_date = QString::fromStdString(volume->GetApploaderDate());
|
||||
|
||||
ReadBanner(*volume);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameFile::TryLoadElfDol()
|
||||
{
|
||||
if (!IsElfOrDol())
|
||||
return false;
|
||||
|
||||
m_revision = 0;
|
||||
m_platform = DiscIO::Platform::ELF_DOL;
|
||||
m_region = DiscIO::Region::UNKNOWN_REGION;
|
||||
m_country = DiscIO::Country::COUNTRY_UNKNOWN;
|
||||
m_blob_type = DiscIO::BlobType::DIRECTORY;
|
||||
m_raw_size = m_size;
|
||||
m_rating = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GameFile::GetFileName() const
|
||||
{
|
||||
return QFileInfo(m_path).fileName();
|
||||
}
|
||||
|
||||
QString GameFile::GetFileExtension() const
|
||||
{
|
||||
return QFileInfo(m_path).suffix();
|
||||
}
|
||||
|
||||
QString GameFile::GetFileFolder() const
|
||||
{
|
||||
return QFileInfo(m_path).dir().dirName();
|
||||
}
|
||||
|
||||
QString GameFile::GetBannerString(const QMap<DiscIO::Language, QString>& m) const
|
||||
{
|
||||
// Try the settings language, then English, then just pick one.
|
||||
if (m.isEmpty())
|
||||
return QString();
|
||||
|
||||
bool wii = m_platform != DiscIO::Platform::GAMECUBE_DISC;
|
||||
DiscIO::Language current_lang = SConfig::GetInstance().GetCurrentLanguage(wii);
|
||||
|
||||
if (m.contains(current_lang))
|
||||
return m[current_lang];
|
||||
if (m.contains(DiscIO::Language::LANGUAGE_ENGLISH))
|
||||
return m[DiscIO::Language::LANGUAGE_ENGLISH];
|
||||
return m.first();
|
||||
}
|
||||
|
||||
QString GameFile::GetPlatform() const
|
||||
{
|
||||
switch (m_platform)
|
||||
{
|
||||
case DiscIO::Platform::GAMECUBE_DISC:
|
||||
return QObject::tr("GameCube");
|
||||
case DiscIO::Platform::WII_DISC:
|
||||
return QObject::tr("Wii");
|
||||
case DiscIO::Platform::WII_WAD:
|
||||
return QObject::tr("Wii Channel");
|
||||
case DiscIO::Platform::ELF_DOL:
|
||||
return QObject::tr("ELF/DOL");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString GameFile::GetCountry() const
|
||||
{
|
||||
switch (m_country)
|
||||
{
|
||||
case DiscIO::Country::COUNTRY_EUROPE:
|
||||
return QObject::tr("Europe");
|
||||
case DiscIO::Country::COUNTRY_JAPAN:
|
||||
return QObject::tr("Japan");
|
||||
case DiscIO::Country::COUNTRY_USA:
|
||||
return QObject::tr("USA");
|
||||
case DiscIO::Country::COUNTRY_AUSTRALIA:
|
||||
return QObject::tr("Australia");
|
||||
case DiscIO::Country::COUNTRY_FRANCE:
|
||||
return QObject::tr("France");
|
||||
case DiscIO::Country::COUNTRY_GERMANY:
|
||||
return QObject::tr("Germany");
|
||||
case DiscIO::Country::COUNTRY_ITALY:
|
||||
return QObject::tr("Italy");
|
||||
case DiscIO::Country::COUNTRY_KOREA:
|
||||
return QObject::tr("Korea");
|
||||
case DiscIO::Country::COUNTRY_NETHERLANDS:
|
||||
return QObject::tr("Netherlands");
|
||||
case DiscIO::Country::COUNTRY_RUSSIA:
|
||||
return QObject::tr("Russia");
|
||||
case DiscIO::Country::COUNTRY_SPAIN:
|
||||
return QObject::tr("Spain");
|
||||
case DiscIO::Country::COUNTRY_TAIWAN:
|
||||
return QObject::tr("Taiwan");
|
||||
case DiscIO::Country::COUNTRY_WORLD:
|
||||
return QObject::tr("World");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString GameFile::GetLanguage(DiscIO::Language lang) const
|
||||
{
|
||||
switch (lang)
|
||||
{
|
||||
case DiscIO::Language::LANGUAGE_JAPANESE:
|
||||
return QObject::tr("Japanese");
|
||||
case DiscIO::Language::LANGUAGE_ENGLISH:
|
||||
return QObject::tr("English");
|
||||
case DiscIO::Language::LANGUAGE_GERMAN:
|
||||
return QObject::tr("German");
|
||||
case DiscIO::Language::LANGUAGE_FRENCH:
|
||||
return QObject::tr("French");
|
||||
case DiscIO::Language::LANGUAGE_SPANISH:
|
||||
return QObject::tr("Spanish");
|
||||
case DiscIO::Language::LANGUAGE_ITALIAN:
|
||||
return QObject::tr("Italian");
|
||||
case DiscIO::Language::LANGUAGE_DUTCH:
|
||||
return QObject::tr("Dutch");
|
||||
case DiscIO::Language::LANGUAGE_SIMPLIFIED_CHINESE:
|
||||
return QObject::tr("Simplified Chinese");
|
||||
case DiscIO::Language::LANGUAGE_TRADITIONAL_CHINESE:
|
||||
return QObject::tr("Traditional Chinese");
|
||||
case DiscIO::Language::LANGUAGE_KOREAN:
|
||||
return QObject::tr("Korean");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString GameFile::GetUniqueID() const
|
||||
{
|
||||
std::vector<std::string> info;
|
||||
if (!GetGameID().isEmpty())
|
||||
info.push_back(GetGameID().toStdString());
|
||||
|
||||
if (GetRevision() != 0)
|
||||
{
|
||||
info.push_back("Revision " + std::to_string(GetRevision()));
|
||||
}
|
||||
|
||||
std::string name = m_long_names[DiscIO::Language::LANGUAGE_ENGLISH].toStdString();
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
if (!m_long_names.isEmpty())
|
||||
name = m_long_names.begin().value().toStdString();
|
||||
else
|
||||
{
|
||||
std::string filename, extension;
|
||||
name = SplitPath(m_path.toStdString(), nullptr, &filename, &extension);
|
||||
name = filename + extension;
|
||||
}
|
||||
}
|
||||
|
||||
int disc_number = GetDiscNumber() + 1;
|
||||
|
||||
std::string lower_name = name;
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
|
||||
if (disc_number > 1 &&
|
||||
lower_name.find(std::string("disc ") + std::to_string(disc_number)) == std::string::npos &&
|
||||
lower_name.find(std::string("disc") + std::to_string(disc_number)) == std::string::npos)
|
||||
{
|
||||
info.push_back("Disc " + std::to_string(disc_number));
|
||||
}
|
||||
|
||||
if (info.empty())
|
||||
return QString::fromStdString(name);
|
||||
|
||||
std::ostringstream ss;
|
||||
std::copy(info.begin(), info.end() - 1, std::ostream_iterator<std::string>(ss, ", "));
|
||||
ss << info.back();
|
||||
return QString::fromStdString(name + " (" + ss.str() + ")");
|
||||
}
|
||||
|
||||
bool GameFile::IsInstalled() const
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
const std::string content_dir =
|
||||
Common::GetTitleContentPath(m_title_id, Common::FromWhichRoot::FROM_CONFIGURED_ROOT);
|
||||
|
||||
if (!File::IsDirectory(content_dir))
|
||||
return false;
|
||||
|
||||
// Since this isn't IOS and we only need a simple way to figure out if a title is installed,
|
||||
// we make the (reasonable) assumption that having more than just the TMD in the content
|
||||
// directory means that the title is installed.
|
||||
const auto entries = File::ScanDirectoryTree(content_dir, false);
|
||||
return std::any_of(entries.children.begin(), entries.children.end(),
|
||||
[](const auto& file) { return file.virtualName != "title.tmd"; });
|
||||
}
|
||||
|
||||
bool GameFile::Install()
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
bool installed = WiiUtils::InstallWAD(m_path.toStdString());
|
||||
|
||||
if (installed)
|
||||
Settings::Instance().NANDRefresh();
|
||||
|
||||
return installed;
|
||||
}
|
||||
|
||||
bool GameFile::Uninstall()
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
IOS::HLE::Kernel ios;
|
||||
return ios.GetES()->DeleteTitleContent(m_title_id) == IOS::HLE::IPC_SUCCESS;
|
||||
}
|
||||
|
||||
bool GameFile::ExportWiiSave()
|
||||
{
|
||||
return CWiiSaveCrypted::ExportWiiSave(m_title_id);
|
||||
}
|
||||
|
||||
QString GameFile::GetWiiFSPath() const
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_DISC || m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
const std::string path = Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT);
|
||||
|
||||
return QString::fromStdString(path);
|
||||
}
|
||||
|
||||
// Convert an integer size to a friendly string representation.
|
||||
QString FormatSize(qint64 size)
|
||||
{
|
||||
QStringList units{QStringLiteral("KB"), QStringLiteral("MB"), QStringLiteral("GB"),
|
||||
QStringLiteral("TB")};
|
||||
QStringListIterator i(units);
|
||||
QString unit = QStringLiteral("B");
|
||||
double num = (double)size;
|
||||
while (num > 1024.0 && i.hasNext())
|
||||
{
|
||||
unit = i.next();
|
||||
num /= 1024.0;
|
||||
}
|
||||
return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit);
|
||||
}
|
||||
|
||||
template <typename T, typename U = std::enable_if_t<std::is_enum<T>::value>>
|
||||
QDataStream& operator<<(QDataStream& out, const T& enum_value)
|
||||
{
|
||||
out << static_cast<std::underlying_type_t<T>>(enum_value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename U = std::enable_if_t<std::is_enum<T>::value>>
|
||||
QDataStream& operator>>(QDataStream& in, T& enum_value)
|
||||
{
|
||||
std::underlying_type_t<T> tmp;
|
||||
in >> tmp;
|
||||
enum_value = static_cast<T>(tmp);
|
||||
return in;
|
||||
}
|
||||
|
||||
// Some C++ implementations define uint64_t as an 'unsigned long', but QDataStream only has built-in
|
||||
// overloads for quint64, which is an 'unsigned long long' on Unix
|
||||
QDataStream& operator<<(QDataStream& out, const unsigned long& integer)
|
||||
{
|
||||
out << static_cast<quint64>(integer);
|
||||
return out;
|
||||
}
|
||||
QDataStream& operator>>(QDataStream& in, unsigned long& integer)
|
||||
{
|
||||
quint64 tmp;
|
||||
in >> tmp;
|
||||
integer = static_cast<unsigned long>(tmp);
|
||||
return in;
|
||||
}
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const GameFile& file)
|
||||
{
|
||||
out << file.m_last_modified;
|
||||
out << file.m_path;
|
||||
out << file.m_title_id;
|
||||
out << file.m_game_id;
|
||||
out << file.m_maker_id;
|
||||
out << file.m_maker;
|
||||
out << file.m_long_makers;
|
||||
out << file.m_short_makers;
|
||||
out << file.m_internal_name;
|
||||
out << file.m_long_names;
|
||||
out << file.m_short_names;
|
||||
out << file.m_platform;
|
||||
out << file.m_region;
|
||||
out << file.m_country;
|
||||
out << file.m_blob_type;
|
||||
out << file.m_size;
|
||||
out << file.m_raw_size;
|
||||
out << file.m_descriptions;
|
||||
out << file.m_revision;
|
||||
out << file.m_disc_number;
|
||||
out << file.m_issues;
|
||||
out << file.m_rating;
|
||||
out << file.m_apploader_date;
|
||||
out << file.m_banner;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream& operator>>(QDataStream& in, GameFile& file)
|
||||
{
|
||||
in >> file.m_last_modified;
|
||||
in >> file.m_path;
|
||||
in >> file.m_title_id;
|
||||
in >> file.m_game_id;
|
||||
in >> file.m_maker_id;
|
||||
in >> file.m_maker;
|
||||
in >> file.m_long_makers;
|
||||
in >> file.m_short_makers;
|
||||
in >> file.m_internal_name;
|
||||
in >> file.m_long_names;
|
||||
in >> file.m_short_names;
|
||||
in >> file.m_platform;
|
||||
in >> file.m_region;
|
||||
in >> file.m_country;
|
||||
in >> file.m_blob_type;
|
||||
in >> file.m_size;
|
||||
in >> file.m_raw_size;
|
||||
in >> file.m_descriptions;
|
||||
in >> file.m_revision;
|
||||
in >> file.m_disc_number;
|
||||
in >> file.m_issues;
|
||||
in >> file.m_rating;
|
||||
in >> file.m_apploader_date;
|
||||
in >> file.m_banner;
|
||||
|
||||
file.m_valid = true;
|
||||
|
||||
return in;
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
enum class BlobType;
|
||||
enum class Country;
|
||||
enum class Language;
|
||||
enum class Region;
|
||||
enum class Platform;
|
||||
class Volume;
|
||||
}
|
||||
|
||||
class GameFile final
|
||||
{
|
||||
public:
|
||||
GameFile();
|
||||
explicit GameFile(const QString& path);
|
||||
|
||||
bool IsValid() const;
|
||||
// These will be properly initialized before we try to load the file.
|
||||
QString GetFilePath() const { return m_path; }
|
||||
QString GetFileName() const;
|
||||
QString GetFileExtension() const;
|
||||
QString GetFileFolder() const;
|
||||
qint64 GetFileSize() const { return m_size; }
|
||||
QDateTime GetLastModified() const { return m_last_modified; }
|
||||
// The rest will not.
|
||||
QString GetGameID() const { return m_game_id; }
|
||||
QString GetMakerID() const { return m_maker_id; }
|
||||
QString GetMaker() const { return m_maker; }
|
||||
u64 GetTitleID() const { return m_title_id; }
|
||||
u16 GetRevision() const { return m_revision; }
|
||||
QString GetInternalName() const { return m_internal_name; }
|
||||
QString GetUniqueID() const;
|
||||
u8 GetDiscNumber() const { return m_disc_number; }
|
||||
u64 GetRawSize() const { return m_raw_size; }
|
||||
QPixmap GetBanner() const { return m_banner; }
|
||||
QString GetIssues() const { return m_issues; }
|
||||
int GetRating() const { return m_rating; }
|
||||
QString GetApploaderDate() const { return m_apploader_date; }
|
||||
DiscIO::Platform GetPlatformID() const { return m_platform; }
|
||||
QString GetPlatform() const;
|
||||
DiscIO::Region GetRegion() const { return m_region; }
|
||||
DiscIO::Country GetCountryID() const { return m_country; }
|
||||
QString GetCountry() const;
|
||||
DiscIO::BlobType GetBlobType() const { return m_blob_type; }
|
||||
QString GetWiiFSPath() const;
|
||||
bool IsInstalled() const;
|
||||
// Banner details
|
||||
QString GetLanguage(DiscIO::Language lang) const;
|
||||
QList<DiscIO::Language> GetAvailableLanguages() const;
|
||||
QString GetShortName() const { return GetBannerString(m_short_names); }
|
||||
QString GetShortMaker() const { return GetBannerString(m_short_makers); }
|
||||
QString GetLongName() const { return GetBannerString(m_long_names); }
|
||||
QString GetLongMaker() const { return GetBannerString(m_long_makers); }
|
||||
QString GetDescription() const { return GetBannerString(m_descriptions); }
|
||||
QString GetShortName(DiscIO::Language lang) const { return m_short_names[lang]; }
|
||||
QString GetShortMaker(DiscIO::Language lang) const { return m_short_makers[lang]; }
|
||||
QString GetLongName(DiscIO::Language lang) const { return m_long_names[lang]; }
|
||||
QString GetLongMaker(DiscIO::Language lang) const { return m_long_makers[lang]; }
|
||||
QString GetDescription(DiscIO::Language lang) const { return m_descriptions[lang]; }
|
||||
bool Install();
|
||||
bool Uninstall();
|
||||
bool ExportWiiSave();
|
||||
|
||||
friend QDataStream& operator<<(QDataStream& out, const GameFile& file);
|
||||
friend QDataStream& operator>>(QDataStream& in, GameFile& file);
|
||||
|
||||
private:
|
||||
QString GetBannerString(const QMap<DiscIO::Language, QString>& m) const;
|
||||
|
||||
void ReadBanner(const DiscIO::Volume& volume);
|
||||
bool LoadFileInfo(const QString& path);
|
||||
void LoadState();
|
||||
bool IsElfOrDol();
|
||||
bool TryLoadElfDol();
|
||||
bool TryLoadVolume();
|
||||
|
||||
bool m_valid;
|
||||
QString m_path;
|
||||
QDateTime m_last_modified;
|
||||
qint64 m_size = 0;
|
||||
|
||||
QString m_game_id;
|
||||
QString m_maker;
|
||||
QString m_maker_id;
|
||||
u16 m_revision = 0;
|
||||
u64 m_title_id = 0;
|
||||
QString m_internal_name;
|
||||
QMap<DiscIO::Language, QString> m_short_names;
|
||||
QMap<DiscIO::Language, QString> m_long_names;
|
||||
QMap<DiscIO::Language, QString> m_short_makers;
|
||||
QMap<DiscIO::Language, QString> m_long_makers;
|
||||
QMap<DiscIO::Language, QString> m_descriptions;
|
||||
u8 m_disc_number = 0;
|
||||
DiscIO::Region m_region;
|
||||
DiscIO::Platform m_platform;
|
||||
DiscIO::Country m_country;
|
||||
DiscIO::BlobType m_blob_type;
|
||||
u64 m_raw_size = 0;
|
||||
QPixmap m_banner;
|
||||
QString m_issues;
|
||||
int m_rating = 0;
|
||||
QString m_apploader_date;
|
||||
};
|
||||
|
||||
QString FormatSize(qint64 size);
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const GameFile& file);
|
||||
QDataStream& operator>>(QDataStream& in, GameFile& file);
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const unsigned long& file);
|
||||
QDataStream& operator>>(QDataStream& in, unsigned long& file);
|
@ -1,76 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "GameFileCache.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
|
||||
static const int CACHE_VERSION = 4; // Last changed in PR #6109
|
||||
static const int DATASTREAM_VERSION = QDataStream::Qt_5_0;
|
||||
|
||||
GameFileCache::GameFileCache()
|
||||
: m_path(QString::fromStdString(File::GetUserPath(D_CACHE_IDX) + "qt_gamefile.cache"))
|
||||
{
|
||||
}
|
||||
|
||||
bool GameFileCache::IsCached(const QString& path) const
|
||||
{
|
||||
return m_gamefiles.contains(path);
|
||||
}
|
||||
|
||||
GameFile GameFileCache::GetFile(const QString& path) const
|
||||
{
|
||||
return m_gamefiles[path];
|
||||
}
|
||||
|
||||
void GameFileCache::Load()
|
||||
{
|
||||
QFile file(m_path);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
QDataStream stream(&file);
|
||||
stream.setVersion(DATASTREAM_VERSION);
|
||||
|
||||
qint32 cache_version;
|
||||
stream >> cache_version;
|
||||
|
||||
// If the cache file is using an older version, ignore it and create it from scratch
|
||||
if (cache_version != CACHE_VERSION)
|
||||
return;
|
||||
|
||||
stream >> m_gamefiles;
|
||||
}
|
||||
|
||||
void GameFileCache::Save() const
|
||||
{
|
||||
QFile file(m_path);
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
|
||||
QDataStream stream(&file);
|
||||
stream.setVersion(DATASTREAM_VERSION);
|
||||
|
||||
stream << static_cast<qint32>(CACHE_VERSION);
|
||||
stream << m_gamefiles;
|
||||
}
|
||||
|
||||
void GameFileCache::Update(const GameFile& gamefile)
|
||||
{
|
||||
m_gamefiles[gamefile.GetFilePath()] = gamefile;
|
||||
}
|
||||
|
||||
QList<QString> GameFileCache::GetCached() const
|
||||
{
|
||||
return m_gamefiles.keys();
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
|
||||
class GameFileCache
|
||||
{
|
||||
public:
|
||||
explicit GameFileCache();
|
||||
|
||||
void Update(const GameFile& gamefile);
|
||||
void Save() const;
|
||||
void Load();
|
||||
bool IsCached(const QString& path) const;
|
||||
GameFile GetFile(const QString& path) const;
|
||||
QList<QString> GetCached() const;
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
|
||||
QMap<QString, GameFile> m_gamefiles;
|
||||
};
|
@ -21,6 +21,8 @@
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/WiiSaveCrypted.h"
|
||||
#include "Core/WiiUtils.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
|
||||
@ -157,11 +159,11 @@ void GameList::MakeGridView()
|
||||
void GameList::ShowContextMenu(const QPoint&)
|
||||
{
|
||||
const auto game = GetSelectedGame();
|
||||
if (game.isNull())
|
||||
if (!game)
|
||||
return;
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
DiscIO::Platform platform = game->GetPlatformID();
|
||||
DiscIO::Platform platform = game->GetPlatform();
|
||||
AddAction(menu, tr("&Properties"), this, &GameList::OpenProperties);
|
||||
AddAction(menu, tr("&Wiki"), this, &GameList::OpenWiki);
|
||||
menu->addSeparator();
|
||||
@ -188,7 +190,7 @@ void GameList::ShowContextMenu(const QPoint&)
|
||||
if (platform == DiscIO::Platform::WII_DISC)
|
||||
{
|
||||
auto* perform_disc_update = AddAction(menu, tr("Perform System Update"), this, [this] {
|
||||
WiiUpdate::PerformDiscUpdate(GetSelectedGame()->GetFilePath().toStdString(), this);
|
||||
WiiUpdate::PerformDiscUpdate(GetSelectedGame()->GetFilePath(), this);
|
||||
});
|
||||
perform_disc_update->setEnabled(!Core::IsRunning() || !SConfig::GetInstance().bWii);
|
||||
}
|
||||
@ -209,7 +211,8 @@ void GameList::ShowContextMenu(const QPoint&)
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
|
||||
wad_install_action->setEnabled(state == Core::State::Uninitialized);
|
||||
wad_uninstall_action->setEnabled(state == Core::State::Uninitialized && game->IsInstalled());
|
||||
wad_uninstall_action->setEnabled(state == Core::State::Uninitialized &&
|
||||
WiiUtils::IsTitleInstalled(game->GetTitleID()));
|
||||
});
|
||||
|
||||
menu->addSeparator();
|
||||
@ -228,7 +231,7 @@ void GameList::ShowContextMenu(const QPoint&)
|
||||
QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
|
||||
|
||||
connect(netplay_host, &QAction::triggered,
|
||||
[this, game] { emit NetPlayHost(game->GetUniqueID()); });
|
||||
[this, game] { emit NetPlayHost(QString::fromStdString(game->GetUniqueIdentifier())); });
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
|
||||
netplay_host->setEnabled(state == Core::State::Uninitialized);
|
||||
@ -253,7 +256,7 @@ void GameList::ExportWiiSave()
|
||||
{
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GetSelectedGame()->ExportWiiSave();
|
||||
const bool success = CWiiSaveCrypted::ExportWiiSave(GetSelectedGame()->GetTitleID());
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Successfully exported save files") :
|
||||
@ -263,7 +266,7 @@ void GameList::ExportWiiSave()
|
||||
|
||||
void GameList::OpenWiki()
|
||||
{
|
||||
QString game_id = GetSelectedGame()->GetGameID();
|
||||
QString game_id = QString::fromStdString(GetSelectedGame()->GetGameID());
|
||||
QString url = QStringLiteral("https://wiki.dolphin-emu.org/index.php?title=").append(game_id);
|
||||
QDesktopServices::openUrl(QUrl(url));
|
||||
}
|
||||
@ -275,7 +278,7 @@ void GameList::CompressISO()
|
||||
|
||||
const bool compressed = (file->GetBlobType() == DiscIO::BlobType::GCZ);
|
||||
|
||||
if (!compressed && file->GetPlatformID() == DiscIO::Platform::WII_DISC)
|
||||
if (!compressed && file->GetPlatform() == DiscIO::Platform::WII_DISC)
|
||||
{
|
||||
QMessageBox wii_warning(this);
|
||||
wii_warning.setIcon(QMessageBox::Warning);
|
||||
@ -292,9 +295,9 @@ void GameList::CompressISO()
|
||||
QString dst_path = QFileDialog::getSaveFileName(
|
||||
this, compressed ? tr("Select where you want to save the decompressed image") :
|
||||
tr("Select where you want to save the compressed image"),
|
||||
QFileInfo(GetSelectedGame()->GetFilePath())
|
||||
QFileInfo(QString::fromStdString(GetSelectedGame()->GetFilePath()))
|
||||
.dir()
|
||||
.absoluteFilePath(file->GetGameID())
|
||||
.absoluteFilePath(QString::fromStdString(file->GetGameID()))
|
||||
.append(compressed ? QStringLiteral(".gcm") : QStringLiteral(".gcz")),
|
||||
compressed ? tr("Uncompressed GC/Wii images (*.iso *.gcm)") :
|
||||
tr("Compressed GC/Wii images (*.gcz)"));
|
||||
@ -310,13 +313,13 @@ void GameList::CompressISO()
|
||||
|
||||
if (compressed)
|
||||
{
|
||||
good = DiscIO::DecompressBlobToFile(original_path.toStdString(), dst_path.toStdString(),
|
||||
&CompressCB, &progress_dialog);
|
||||
good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(), &CompressCB,
|
||||
&progress_dialog);
|
||||
}
|
||||
else
|
||||
{
|
||||
good = DiscIO::CompressFileToBlob(original_path.toStdString(), dst_path.toStdString(),
|
||||
file->GetPlatformID() == DiscIO::Platform::WII_DISC ? 1 : 0,
|
||||
good = DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(),
|
||||
file->GetPlatform() == DiscIO::Platform::WII_DISC ? 1 : 0,
|
||||
16384, &CompressCB, &progress_dialog);
|
||||
}
|
||||
|
||||
@ -336,7 +339,7 @@ void GameList::InstallWAD()
|
||||
{
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GetSelectedGame()->Install();
|
||||
const bool success = WiiUtils::InstallWAD(GetSelectedGame()->GetFilePath());
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Successfully installed this title to the NAND.") :
|
||||
@ -358,7 +361,7 @@ void GameList::UninstallWAD()
|
||||
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GetSelectedGame()->Uninstall();
|
||||
const bool success = WiiUtils::UninstallTitle(GetSelectedGame()->GetTitleID());
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Successfully removed this title from the NAND.") :
|
||||
@ -368,24 +371,25 @@ void GameList::UninstallWAD()
|
||||
|
||||
void GameList::SetDefaultISO()
|
||||
{
|
||||
Settings::Instance().SetDefaultGame(GetSelectedGame()->GetFilePath());
|
||||
SConfig::GetInstance().m_strDefaultISO = GetSelectedGame()->GetFilePath();
|
||||
}
|
||||
|
||||
void GameList::OpenContainingFolder()
|
||||
{
|
||||
QUrl url = QUrl::fromLocalFile(QFileInfo(GetSelectedGame()->GetFilePath()).dir().absolutePath());
|
||||
QUrl url = QUrl::fromLocalFile(
|
||||
QFileInfo(QString::fromStdString(GetSelectedGame()->GetFilePath())).dir().absolutePath());
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void GameList::OpenSaveFolder()
|
||||
{
|
||||
QUrl url = QUrl::fromLocalFile(GetSelectedGame()->GetWiiFSPath());
|
||||
QUrl url = QUrl::fromLocalFile(QString::fromStdString(GetSelectedGame()->GetWiiFSPath()));
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void GameList::DeleteFile()
|
||||
{
|
||||
const auto game = GetSelectedGame()->GetFilePath();
|
||||
const std::string game = GetSelectedGame()->GetFilePath();
|
||||
QMessageBox confirm_dialog(this);
|
||||
|
||||
confirm_dialog.setIcon(QMessageBox::Warning);
|
||||
@ -399,7 +403,7 @@ void GameList::DeleteFile()
|
||||
|
||||
while (!deletion_successful)
|
||||
{
|
||||
deletion_successful = File::Delete(game.toStdString());
|
||||
deletion_successful = File::Delete(game);
|
||||
|
||||
if (deletion_successful)
|
||||
{
|
||||
@ -424,11 +428,10 @@ void GameList::DeleteFile()
|
||||
|
||||
void GameList::ChangeDisc()
|
||||
{
|
||||
Core::RunAsCPUThread(
|
||||
[this] { DVDInterface::ChangeDisc(GetSelectedGame()->GetFilePath().toStdString()); });
|
||||
Core::RunAsCPUThread([this] { DVDInterface::ChangeDisc(GetSelectedGame()->GetFilePath()); });
|
||||
}
|
||||
|
||||
QSharedPointer<GameFile> GameList::GetSelectedGame() const
|
||||
std::shared_ptr<const UICommon::GameFile> GameList::GetSelectedGame() const
|
||||
{
|
||||
QAbstractItemView* view;
|
||||
QSortFilterProxyModel* proxy;
|
||||
|
@ -4,22 +4,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStackedWidget>
|
||||
#include <QTableView>
|
||||
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/GameList/GameListModel.h"
|
||||
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class GameList final : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GameList(QWidget* parent = nullptr);
|
||||
QSharedPointer<GameFile> GetSelectedGame() const;
|
||||
std::shared_ptr<const UICommon::GameFile> GetSelectedGame() const;
|
||||
|
||||
void SetListView() { SetPreferredView(true); }
|
||||
void SetGridView() { SetPreferredView(false); }
|
||||
@ -30,7 +33,7 @@ public:
|
||||
signals:
|
||||
void GameSelected();
|
||||
void NetPlayHost(const QString& game_id);
|
||||
void SelectionChanged(QSharedPointer<GameFile> game_file);
|
||||
void SelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file);
|
||||
void OpenGeneralSettings();
|
||||
|
||||
private:
|
||||
|
@ -3,17 +3,23 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt2/GameList/GameListModel.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DolphinQt2/QtUtils/ImageConverter.h"
|
||||
#include "DolphinQt2/Resources.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
#include "UICommon/UICommon.h"
|
||||
|
||||
const QSize GAMECUBE_BANNER_SIZE(96, 32);
|
||||
|
||||
GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent)
|
||||
{
|
||||
connect(&m_tracker, &GameTracker::GameLoaded, this, &GameListModel::UpdateGame);
|
||||
connect(&m_tracker, &GameTracker::GameRemoved, this, &GameListModel::RemoveGame);
|
||||
connect(&m_tracker, &GameTracker::GameRemoved, this,
|
||||
[this](const QString& path) { RemoveGame(path.toStdString()); });
|
||||
connect(&Settings::Instance(), &Settings::PathAdded, &m_tracker, &GameTracker::AddDirectory);
|
||||
connect(&Settings::Instance(), &Settings::PathRemoved, &m_tracker, &GameTracker::RemoveDirectory);
|
||||
|
||||
@ -26,8 +32,6 @@ GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent)
|
||||
emit layoutAboutToBeChanged();
|
||||
emit layoutChanged();
|
||||
});
|
||||
|
||||
// TODO: Reload m_title_database when the language changes
|
||||
}
|
||||
|
||||
QVariant GameListModel::data(const QModelIndex& index, int role) const
|
||||
@ -35,78 +39,68 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
QSharedPointer<GameFile> game = m_games[index.row()];
|
||||
const UICommon::GameFile& game = *m_games[index.row()];
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case COL_PLATFORM:
|
||||
if (role == Qt::DecorationRole)
|
||||
return Resources::GetPlatform(static_cast<int>(game->GetPlatformID()));
|
||||
return Resources::GetPlatform(static_cast<int>(game.GetPlatform()));
|
||||
if (role == Qt::InitialSortOrderRole)
|
||||
return static_cast<int>(game->GetPlatformID());
|
||||
return static_cast<int>(game.GetPlatform());
|
||||
break;
|
||||
case COL_COUNTRY:
|
||||
if (role == Qt::DecorationRole)
|
||||
return Resources::GetCountry(static_cast<int>(game->GetCountryID()));
|
||||
return Resources::GetCountry(static_cast<int>(game.GetCountry()));
|
||||
if (role == Qt::InitialSortOrderRole)
|
||||
return static_cast<int>(game->GetCountryID());
|
||||
return static_cast<int>(game.GetCountry());
|
||||
break;
|
||||
case COL_RATING:
|
||||
if (role == Qt::DecorationRole)
|
||||
return Resources::GetRating(game->GetRating());
|
||||
return Resources::GetRating(game.GetEmuState());
|
||||
if (role == Qt::InitialSortOrderRole)
|
||||
return game->GetRating();
|
||||
return game.GetEmuState();
|
||||
break;
|
||||
case COL_BANNER:
|
||||
if (role == Qt::DecorationRole)
|
||||
{
|
||||
// GameCube banners are 96x32, but Wii banners are 192x64.
|
||||
// TODO: use custom banners from rom directory like DolphinWX?
|
||||
QPixmap banner = game->GetBanner();
|
||||
QPixmap banner = ToQPixmap(game.GetBannerImage());
|
||||
if (banner.isNull())
|
||||
banner = Resources::GetMisc(Resources::BANNER_MISSING);
|
||||
banner.setDevicePixelRatio(std::max(banner.width() / GAMECUBE_BANNER_SIZE.width(),
|
||||
banner.height() / GAMECUBE_BANNER_SIZE.height()));
|
||||
|
||||
banner.setDevicePixelRatio(
|
||||
std::max(static_cast<qreal>(banner.width()) / GAMECUBE_BANNER_SIZE.width(),
|
||||
static_cast<qreal>(banner.height()) / GAMECUBE_BANNER_SIZE.height()));
|
||||
|
||||
return banner;
|
||||
}
|
||||
break;
|
||||
case COL_TITLE:
|
||||
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||
{
|
||||
QString display_name = QString::fromStdString(m_title_database.GetTitleName(
|
||||
game->GetGameID().toStdString(), game->GetPlatformID() == DiscIO::Platform::WII_WAD ?
|
||||
Core::TitleDatabase::TitleType::Channel :
|
||||
Core::TitleDatabase::TitleType::Other));
|
||||
if (display_name.isEmpty())
|
||||
display_name = game->GetLongName();
|
||||
|
||||
if (display_name.isEmpty())
|
||||
display_name = game->GetFileName();
|
||||
|
||||
return display_name;
|
||||
}
|
||||
return QString::fromStdString(game.GetName());
|
||||
break;
|
||||
case COL_ID:
|
||||
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||
return game->GetGameID();
|
||||
return QString::fromStdString(game.GetGameID());
|
||||
break;
|
||||
case COL_DESCRIPTION:
|
||||
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||
return game->GetDescription();
|
||||
return QString::fromStdString(game.GetDescription());
|
||||
break;
|
||||
case COL_MAKER:
|
||||
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||
return game->GetMaker();
|
||||
return QString::fromStdString(game.GetMaker());
|
||||
break;
|
||||
case COL_FILE_NAME:
|
||||
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||
return game->GetFileName();
|
||||
return QString::fromStdString(game.GetFileName());
|
||||
break;
|
||||
case COL_SIZE:
|
||||
if (role == Qt::DisplayRole)
|
||||
return FormatSize(game->GetFileSize());
|
||||
return QString::fromStdString(UICommon::FormatSize(game.GetFileSize()));
|
||||
if (role == Qt::InitialSortOrderRole)
|
||||
return game->GetFileSize();
|
||||
return static_cast<quint64>(game.GetFileSize());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -154,10 +148,10 @@ int GameListModel::columnCount(const QModelIndex& parent) const
|
||||
|
||||
bool GameListModel::ShouldDisplayGameListItem(int index) const
|
||||
{
|
||||
QSharedPointer<GameFile> game = m_games[index];
|
||||
const UICommon::GameFile& game = *m_games[index];
|
||||
|
||||
const bool show_platform = [&game] {
|
||||
switch (game->GetPlatformID())
|
||||
switch (game.GetPlatform())
|
||||
{
|
||||
case DiscIO::Platform::GAMECUBE_DISC:
|
||||
return SConfig::GetInstance().m_ListGC;
|
||||
@ -175,7 +169,7 @@ bool GameListModel::ShouldDisplayGameListItem(int index) const
|
||||
if (!show_platform)
|
||||
return false;
|
||||
|
||||
switch (game->GetCountryID())
|
||||
switch (game.GetCountry())
|
||||
{
|
||||
case DiscIO::Country::COUNTRY_AUSTRALIA:
|
||||
return SConfig::GetInstance().m_ListAustralia;
|
||||
@ -209,16 +203,14 @@ bool GameListModel::ShouldDisplayGameListItem(int index) const
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<GameFile> GameListModel::GetGameFile(int index) const
|
||||
std::shared_ptr<const UICommon::GameFile> GameListModel::GetGameFile(int index) const
|
||||
{
|
||||
return m_games[index];
|
||||
}
|
||||
|
||||
void GameListModel::UpdateGame(const QSharedPointer<GameFile>& game)
|
||||
void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game)
|
||||
{
|
||||
QString path = game->GetFilePath();
|
||||
|
||||
int index = FindGame(path);
|
||||
int index = FindGame(game->GetFilePath());
|
||||
if (index < 0)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_games.size(), m_games.size());
|
||||
@ -232,7 +224,7 @@ void GameListModel::UpdateGame(const QSharedPointer<GameFile>& game)
|
||||
}
|
||||
}
|
||||
|
||||
void GameListModel::RemoveGame(const QString& path)
|
||||
void GameListModel::RemoveGame(const std::string& path)
|
||||
{
|
||||
int entry = FindGame(path);
|
||||
if (entry < 0)
|
||||
@ -243,7 +235,7 @@ void GameListModel::RemoveGame(const QString& path)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
int GameListModel::FindGame(const QString& path) const
|
||||
int GameListModel::FindGame(const std::string& path) const
|
||||
{
|
||||
for (int i = 0; i < m_games.size(); i++)
|
||||
{
|
||||
|
@ -4,12 +4,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QString>
|
||||
|
||||
#include "Core/TitleDatabase.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/GameList/GameTracker.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class GameListModel final : public QAbstractTableModel
|
||||
{
|
||||
@ -25,11 +27,14 @@ public:
|
||||
int rowCount(const QModelIndex& parent) const override;
|
||||
int columnCount(const QModelIndex& parent) const override;
|
||||
|
||||
QSharedPointer<GameFile> GetGameFile(int index) const;
|
||||
// Path of the Game at the specified index.
|
||||
QString GetPath(int index) const { return m_games[index]->GetFilePath(); }
|
||||
// Unique ID of the Game at the specified index
|
||||
QString GetUniqueID(int index) const { return m_games[index]->GetUniqueID(); }
|
||||
std::shared_ptr<const UICommon::GameFile> GetGameFile(int index) const;
|
||||
// Path of the game at the specified index.
|
||||
QString GetPath(int index) const { return QString::fromStdString(m_games[index]->GetFilePath()); }
|
||||
// Unique identifier of the game at the specified index.
|
||||
QString GetUniqueIdentifier(int index) const
|
||||
{
|
||||
return QString::fromStdString(m_games[index]->GetUniqueIdentifier());
|
||||
}
|
||||
bool ShouldDisplayGameListItem(int index) const;
|
||||
enum
|
||||
{
|
||||
@ -46,14 +51,13 @@ public:
|
||||
NUM_COLS
|
||||
};
|
||||
|
||||
void UpdateGame(const QSharedPointer<GameFile>& game);
|
||||
void RemoveGame(const QString& path);
|
||||
void UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game);
|
||||
void RemoveGame(const std::string& path);
|
||||
|
||||
private:
|
||||
// Index in m_games, or -1 if it isn't found
|
||||
int FindGame(const QString& path) const;
|
||||
int FindGame(const std::string& path) const;
|
||||
|
||||
GameTracker m_tracker;
|
||||
QList<QSharedPointer<GameFile>> m_games;
|
||||
Core::TitleDatabase m_title_database;
|
||||
QList<std::shared_ptr<const UICommon::GameFile>> m_games;
|
||||
};
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <QFile>
|
||||
|
||||
#include "DiscIO/DirectoryBlob.h"
|
||||
#include "DolphinQt2/GameList/GameFileCache.h"
|
||||
#include "DolphinQt2/GameList/GameTracker.h"
|
||||
#include "DolphinQt2/QtUtils/QueueOnObject.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
@ -19,13 +18,15 @@ static const QStringList game_filters{
|
||||
|
||||
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
|
||||
{
|
||||
qRegisterMetaType<QSharedPointer<GameFile>>();
|
||||
qRegisterMetaType<std::shared_ptr<const UICommon::GameFile>>();
|
||||
connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory);
|
||||
connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile);
|
||||
|
||||
cache.Load();
|
||||
m_cache.Load();
|
||||
|
||||
m_load_thread.Reset([this](const QString& path) { LoadGame(path); });
|
||||
|
||||
// TODO: When language changes, reload m_title_database and call m_cache.UpdateAdditionalMetadata
|
||||
}
|
||||
|
||||
void GameTracker::AddDirectory(const QString& dir)
|
||||
@ -130,25 +131,12 @@ void GameTracker::UpdateFile(const QString& file)
|
||||
|
||||
void GameTracker::LoadGame(const QString& path)
|
||||
{
|
||||
if (!DiscIO::ShouldHideFromGameList(path.toStdString()))
|
||||
const std::string converted_path = path.toStdString();
|
||||
if (!DiscIO::ShouldHideFromGameList(converted_path))
|
||||
{
|
||||
if (cache.IsCached(path))
|
||||
{
|
||||
const QDateTime last_modified = QFileInfo(path).lastModified();
|
||||
auto cached_file = cache.GetFile(path);
|
||||
if (cached_file.GetLastModified() >= last_modified)
|
||||
{
|
||||
emit GameLoaded(QSharedPointer<GameFile>::create(cached_file));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto game = QSharedPointer<GameFile>::create(path);
|
||||
if (game->IsValid())
|
||||
{
|
||||
emit GameLoaded(game);
|
||||
cache.Update(*game);
|
||||
cache.Save();
|
||||
}
|
||||
bool cache_changed = false;
|
||||
emit GameLoaded(m_cache.AddOrGet(converted_path, &cache_changed, m_title_database));
|
||||
if (cache_changed)
|
||||
m_cache.Save();
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "Common/WorkQueueThread.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/GameList/GameFileCache.h"
|
||||
#include "Core/TitleDatabase.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
#include "UICommon/GameFileCache.h"
|
||||
|
||||
// Watches directories and loads GameFiles in a separate thread.
|
||||
// To use this, just add directories using AddDirectory, and listen for the
|
||||
@ -28,7 +30,7 @@ public:
|
||||
void RemoveDirectory(const QString& dir);
|
||||
|
||||
signals:
|
||||
void GameLoaded(QSharedPointer<GameFile> game);
|
||||
void GameLoaded(std::shared_ptr<const UICommon::GameFile> game);
|
||||
void GameRemoved(const QString& path);
|
||||
|
||||
private:
|
||||
@ -40,7 +42,8 @@ private:
|
||||
// game path -> directories that track it
|
||||
QMap<QString, QSet<QString>> m_tracked_files;
|
||||
Common::WorkQueueThread<QString> m_load_thread;
|
||||
GameFileCache cache;
|
||||
UICommon::GameFileCache m_cache;
|
||||
Core::TitleDatabase m_title_database;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QSharedPointer<GameFile>)
|
||||
Q_DECLARE_METATYPE(std::shared_ptr<const UICommon::GameFile>)
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
|
||||
#include "DolphinQt2/GameList/GameListModel.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDropEvent>
|
||||
@ -386,7 +387,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||
}
|
||||
else
|
||||
{
|
||||
QSharedPointer<GameFile> selection = m_game_list->GetSelectedGame();
|
||||
std::shared_ptr<const UICommon::GameFile> selection = m_game_list->GetSelectedGame();
|
||||
if (selection)
|
||||
{
|
||||
StartGame(selection->GetFilePath(), savestate_path);
|
||||
@ -394,7 +395,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto default_path = QString::fromStdString(SConfig::GetInstance().m_strDefaultISO);
|
||||
QString default_path = QString::fromStdString(SConfig::GetInstance().m_strDefaultISO);
|
||||
if (!default_path.isEmpty() && QFile::exists(default_path))
|
||||
{
|
||||
StartGame(default_path, savestate_path);
|
||||
@ -536,7 +537,13 @@ void MainWindow::ScreenShot()
|
||||
|
||||
void MainWindow::StartGame(const QString& path, const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
StartGame(BootParameters::GenerateFromFile(path.toStdString(), savestate_path));
|
||||
StartGame(path.toStdString(), savestate_path);
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(const std::string& path,
|
||||
const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
StartGame(BootParameters::GenerateFromFile(path, savestate_path));
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "DolphinQt2/GameList/GameList.h"
|
||||
#include "DolphinQt2/MenuBar.h"
|
||||
@ -94,6 +95,7 @@ private:
|
||||
void InitCoreCallbacks();
|
||||
|
||||
void StartGame(const QString& path, const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(const std::string& path, const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(std::unique_ptr<BootParameters>&& parameters);
|
||||
void ShowRenderWidget();
|
||||
void HideRenderWidget();
|
||||
|
@ -34,10 +34,11 @@
|
||||
#include "DiscIO/WiiSaveBanner.h"
|
||||
|
||||
#include "DolphinQt2/AboutDialog.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/QtUtils/ActionHelper.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent)
|
||||
{
|
||||
AddFileMenu();
|
||||
@ -593,8 +594,9 @@ void MenuBar::InstallWAD()
|
||||
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
if (GameFile(wad_file).Install())
|
||||
if (WiiUtils::InstallWAD(wad_file.toStdString()))
|
||||
{
|
||||
Settings::Instance().NANDRefresh();
|
||||
result_dialog.setIcon(QMessageBox::Information);
|
||||
result_dialog.setText(tr("Successfully installed this title to the NAND."));
|
||||
}
|
||||
@ -698,12 +700,12 @@ void MenuBar::NANDExtractCertificates()
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBar::OnSelectionChanged(QSharedPointer<GameFile> game_file)
|
||||
void MenuBar::OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file)
|
||||
{
|
||||
bool is_null = game_file.isNull();
|
||||
const bool game_selected = !!game_file;
|
||||
|
||||
m_recording_play->setEnabled(!Core::IsRunning() && !is_null);
|
||||
m_recording_start->setEnabled(!Movie::IsPlayingInput() && !is_null);
|
||||
m_recording_play->setEnabled(game_selected && !Core::IsRunning());
|
||||
m_recording_start->setEnabled(game_selected && !Movie::IsPlayingInput());
|
||||
}
|
||||
|
||||
void MenuBar::OnRecordingStatusChanged(bool recording)
|
||||
|
@ -5,13 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
enum class State;
|
||||
@ -22,6 +21,11 @@ namespace DiscIO
|
||||
enum class Region;
|
||||
};
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class MenuBar final : public QMenuBar
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -89,7 +93,7 @@ signals:
|
||||
void ExportRecording();
|
||||
void ShowTASInput();
|
||||
|
||||
void SelectionChanged(QSharedPointer<GameFile> game_file);
|
||||
void SelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file);
|
||||
void RecordingStatusChanged(bool recording);
|
||||
void ReadOnlyModeChanged(bool read_only);
|
||||
|
||||
@ -120,7 +124,7 @@ private:
|
||||
void CheckNAND();
|
||||
void NANDExtractCertificates();
|
||||
|
||||
void OnSelectionChanged(QSharedPointer<GameFile> game_file);
|
||||
void OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file);
|
||||
void OnRecordingStatusChanged(bool recording);
|
||||
void OnReadOnlyModeChanged(bool read_only);
|
||||
void OnDebugModeToggled(bool enabled);
|
||||
|
@ -51,7 +51,7 @@ void GameListDialog::PopulateGameList()
|
||||
|
||||
for (int i = 0; i < game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
auto* item = new QListWidgetItem(game_list_model->GetUniqueID(i));
|
||||
auto* item = new QListWidgetItem(game_list_model->GetUniqueIdentifier(i));
|
||||
m_game_list->addItem(item);
|
||||
}
|
||||
|
||||
|
@ -532,7 +532,7 @@ std::string NetPlayDialog::FindGame(const std::string& game)
|
||||
return RunOnObject(this, [this, game] {
|
||||
for (int i = 0; i < m_game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
if (m_game_list_model->GetUniqueID(i).toStdString() == game)
|
||||
if (m_game_list_model->GetUniqueIdentifier(i).toStdString() == game)
|
||||
return m_game_list_model->GetPath(i).toStdString();
|
||||
}
|
||||
return std::string("");
|
||||
|
@ -245,7 +245,7 @@ void NetPlaySetupDialog::PopulateGameList()
|
||||
m_host_games->clear();
|
||||
for (int i = 0; i < m_game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
auto title = m_game_list_model->GetUniqueID(i);
|
||||
auto title = m_game_list_model->GetUniqueIdentifier(i);
|
||||
auto path = m_game_list_model->GetPath(i);
|
||||
|
||||
auto* item = new QListWidgetItem(title);
|
||||
|
33
Source/Core/DolphinQt2/QtUtils/ImageConverter.cpp
Normal file
33
Source/Core/DolphinQt2/QtUtils/ImageConverter.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2018 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt2/QtUtils/ImageConverter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
QPixmap ToQPixmap(const UICommon::GameBanner& banner)
|
||||
{
|
||||
return ToQPixmap(banner.buffer, banner.width, banner.height);
|
||||
}
|
||||
|
||||
QPixmap ToQPixmap(const std::vector<u32>& buffer, int width, int height)
|
||||
{
|
||||
QImage image(width, height, QImage::Format_RGB888);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
const u32 color = buffer[y * width + x];
|
||||
image.setPixel(
|
||||
x, y, qRgb((color & 0xFF0000) >> 16, (color & 0x00FF00) >> 8, (color & 0x0000FF) >> 0));
|
||||
}
|
||||
}
|
||||
|
||||
return QPixmap::fromImage(image);
|
||||
}
|
19
Source/Core/DolphinQt2/QtUtils/ImageConverter.h
Normal file
19
Source/Core/DolphinQt2/QtUtils/ImageConverter.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class QPixmap;
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
struct GameBanner;
|
||||
}
|
||||
|
||||
QPixmap ToQPixmap(const UICommon::GameBanner& banner);
|
||||
QPixmap ToQPixmap(const std::vector<u32>& buffer, int width, int height);
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QPixmap>
|
||||
|
||||
// Store for various QPixmaps that will be used repeatedly.
|
||||
class Resources final
|
||||
|
Reference in New Issue
Block a user