mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
1f1dae367d
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.
213 lines
7.3 KiB
C++
213 lines
7.3 KiB
C++
// Copyright 2016 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <QComboBox>
|
|
#include <QCryptographicHash>
|
|
#include <QFileDialog>
|
|
#include <QFormLayout>
|
|
#include <QGroupBox>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QProgressDialog>
|
|
#include <QPushButton>
|
|
#include <QTextEdit>
|
|
|
|
#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 UICommon::GameFile& game) : m_game(game)
|
|
{
|
|
QVBoxLayout* layout = new QVBoxLayout();
|
|
layout->addWidget(CreateISODetails());
|
|
layout->addWidget(CreateBannerDetails());
|
|
setLayout(layout);
|
|
}
|
|
|
|
QGroupBox* InfoWidget::CreateISODetails()
|
|
{
|
|
QGroupBox* group = new QGroupBox(tr("ISO Details"));
|
|
QFormLayout* layout = new QFormLayout;
|
|
|
|
QLineEdit* file_path = CreateValueDisplay(m_game.GetFilePath());
|
|
QLineEdit* internal_name = CreateValueDisplay(m_game.GetInternalName());
|
|
|
|
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(DiscIO::GetName(m_game.GetCountry(), true));
|
|
QLineEdit* maker = CreateValueDisplay(m_game.GetMaker());
|
|
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(UICommon::FormatSize(m_game.GetFileSize()));
|
|
QWidget* checksum = CreateChecksumComputer();
|
|
|
|
layout->addRow(tr("File Path:"), file_path);
|
|
layout->addRow(tr("Internal Name:"), internal_name);
|
|
layout->addRow(tr("Game ID:"), game_id);
|
|
layout->addRow(tr("Country:"), country);
|
|
layout->addRow(tr("Maker:"), maker);
|
|
layout->addRow(tr("Maker ID:"), maker_id);
|
|
layout->addRow(tr("Disc Number:"), disc_number);
|
|
layout->addRow(tr("Revision:"), revision);
|
|
layout->addRow(tr("Apploader Date:"), apploader_date);
|
|
layout->addRow(tr("ISO Size:"), iso_size);
|
|
layout->addRow(tr("MD5 Checksum:"), checksum);
|
|
|
|
group->setLayout(layout);
|
|
return group;
|
|
}
|
|
|
|
QGroupBox* InfoWidget::CreateBannerDetails()
|
|
{
|
|
QGroupBox* group = new QGroupBox(tr("Banner Details"));
|
|
QFormLayout* layout = new QFormLayout;
|
|
|
|
m_long_name = CreateValueDisplay();
|
|
m_short_name = CreateValueDisplay();
|
|
m_short_maker = CreateValueDisplay();
|
|
m_long_maker = CreateValueDisplay();
|
|
m_description = new QTextEdit();
|
|
m_description->setReadOnly(true);
|
|
CreateLanguageSelector();
|
|
|
|
layout->addRow(tr("Show Language:"), m_language_selector);
|
|
if (m_game.GetPlatform() == DiscIO::Platform::GAMECUBE_DISC)
|
|
{
|
|
layout->addRow(tr("Short Name:"), m_short_name);
|
|
layout->addRow(tr("Short Maker:"), m_short_maker);
|
|
layout->addRow(tr("Long Name:"), m_long_name);
|
|
layout->addRow(tr("Long Maker:"), m_long_maker);
|
|
layout->addRow(tr("Description:"), m_description);
|
|
}
|
|
else if (DiscIO::IsWii(m_game.GetPlatform()))
|
|
{
|
|
layout->addRow(tr("Name:"), m_long_name);
|
|
}
|
|
|
|
QPixmap banner = ToQPixmap(m_game.GetBannerImage());
|
|
if (!banner.isNull())
|
|
layout->addRow(tr("Banner:"), CreateBannerGraphic(banner));
|
|
|
|
group->setLayout(layout);
|
|
return group;
|
|
}
|
|
|
|
QWidget* InfoWidget::CreateBannerGraphic(const QPixmap& image)
|
|
{
|
|
QWidget* widget = new QWidget();
|
|
QHBoxLayout* layout = new QHBoxLayout();
|
|
|
|
QLabel* banner = new QLabel();
|
|
banner->setPixmap(image);
|
|
QPushButton* save = new QPushButton(tr("Save as..."));
|
|
connect(save, &QPushButton::clicked, this, &InfoWidget::SaveBanner);
|
|
|
|
layout->addWidget(banner);
|
|
layout->addWidget(save);
|
|
widget->setLayout(layout);
|
|
return widget;
|
|
}
|
|
|
|
void InfoWidget::SaveBanner()
|
|
{
|
|
QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(),
|
|
tr("PNG image file (*.png);; All Files (*)"));
|
|
ToQPixmap(m_game.GetBannerImage()).save(path, "PNG");
|
|
}
|
|
|
|
QLineEdit* InfoWidget::CreateValueDisplay(const QString& value)
|
|
{
|
|
QLineEdit* value_display = new QLineEdit(value);
|
|
value_display->setReadOnly(true);
|
|
value_display->setCursorPosition(0);
|
|
return value_display;
|
|
}
|
|
|
|
QLineEdit* InfoWidget::CreateValueDisplay(const std::string& value)
|
|
{
|
|
return CreateValueDisplay(QString::fromStdString(value));
|
|
}
|
|
|
|
void InfoWidget::CreateLanguageSelector()
|
|
{
|
|
m_language_selector = new QComboBox();
|
|
for (DiscIO::Language language : m_game.GetLanguages())
|
|
{
|
|
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);
|
|
connect(m_language_selector,
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
&InfoWidget::ChangeLanguage);
|
|
ChangeLanguage();
|
|
}
|
|
|
|
void InfoWidget::ChangeLanguage()
|
|
{
|
|
DiscIO::Language language =
|
|
static_cast<DiscIO::Language>(m_language_selector->currentData().toInt());
|
|
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()
|
|
{
|
|
QWidget* widget = new QWidget();
|
|
QHBoxLayout* layout = new QHBoxLayout();
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
m_checksum_result = new QLineEdit();
|
|
QPushButton* calculate = new QPushButton(tr("Compute"));
|
|
connect(calculate, &QPushButton::clicked, this, &InfoWidget::ComputeChecksum);
|
|
layout->addWidget(m_checksum_result);
|
|
layout->addWidget(calculate);
|
|
|
|
widget->setLayout(layout);
|
|
return widget;
|
|
}
|
|
|
|
void InfoWidget::ComputeChecksum()
|
|
{
|
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
|
hash.reset();
|
|
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;
|
|
|
|
// a maximum of 1000 is used instead of game_size because otherwise 8GB games overflow the int
|
|
// typed maximum parameter
|
|
QProgressDialog* progress =
|
|
new QProgressDialog(tr("Computing MD5 Checksum"), tr("Cancel"), 0, 1000, this);
|
|
progress->setWindowTitle(tr("Computing MD5 Checksum"));
|
|
progress->setMinimumDuration(500);
|
|
progress->setWindowModality(Qt::WindowModal);
|
|
while (read_offset < game_size)
|
|
{
|
|
progress->setValue(static_cast<double>(read_offset) / static_cast<double>(game_size) * 1000);
|
|
if (progress->wasCanceled())
|
|
return;
|
|
|
|
u64 read_size = std::min<u64>(file_data.size(), game_size - read_offset);
|
|
file->Read(read_offset, read_size, file_data.data());
|
|
hash.addData(reinterpret_cast<char*>(file_data.data()), read_size);
|
|
read_offset += read_size;
|
|
}
|
|
m_checksum_result->setText(QString::fromUtf8(hash.result().toHex()));
|
|
Q_ASSERT(read_offset == game_size);
|
|
progress->setValue(1000);
|
|
}
|