Version Manager fixes (#177)

* Version Manager fixes

* ordering

* ordering +

* fix issue 172

* Remove the message, because there are two messages

* Check if version name starts with 'Pre-release' instead of exact match
This commit is contained in:
DanielSvoboda
2025-11-09 02:50:22 -03:00
committed by GitHub
parent 686ec33d72
commit 4d0ce1f959
4 changed files with 219 additions and 43 deletions

View File

@@ -100,6 +100,11 @@ void SaveVersionList(std::vector<Version> const& versions, std::filesystem::path
void AddNewVersion(Version const& v, std::filesystem::path const& path) {
auto versions = GetVersionList(path);
auto it = std::remove_if(versions.begin(), versions.end(),
[&](const Version& existing) { return existing.name == v.name; });
if (it != versions.end())
versions.erase(it, versions.end());
versions.push_back(v);
SaveVersionList(versions, path);
}

View File

@@ -413,9 +413,9 @@ figure_creator_dialog::figure_creator_dialog(QWidget* parent, u8 slot) : QDialog
QHBoxLayout* hbox_filters = new QHBoxLayout();
QLabel* filter_label = new QLabel(tr("Filter by Series:"));
QPushButton* btn_all = new QPushButton(tr("All"));
QPushButton* btn_series1 = new QPushButton(tr("1.0"));
QPushButton* btn_series2 = new QPushButton(tr("2.0"));
QPushButton* btn_series3 = new QPushButton(tr("3.0"));
QPushButton* btn_series1 = new QPushButton("1.0");
QPushButton* btn_series2 = new QPushButton("2.0");
QPushButton* btn_series3 = new QPushButton("3.0");
// Style the active filter button
btn_all->setCheckable(true);

View File

@@ -1426,25 +1426,72 @@ void MainWindow::RestartEmulator() {
void MainWindow::LoadVersionComboBox() {
ui->versionComboBox->clear();
ui->versionComboBox->addItem(tr("None"));
ui->versionComboBox->setCurrentIndex(0);
ui->versionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
QString savedVersionPath = m_gui_settings->GetValue(gui::vm_versionSelected).toString();
auto versions = VersionManager::GetVersionList();
auto const& versions = VersionManager::GetVersionList();
for (auto const& v : versions) {
std::sort(versions.begin(), versions.end(), [](const auto& a, const auto& b) {
auto getOrder = [](int type) {
switch (type) {
case 1: // Pre-release
return 0;
case 0: // Release
return 1;
case 2: // Local
return 2;
default:
return 3;
}
};
int orderA = getOrder(static_cast<int>(a.type));
int orderB = getOrder(static_cast<int>(b.type));
if (orderA != orderB)
return orderA < orderB;
if (a.type == VersionManager::VersionType::Release) {
static QRegularExpression versionRegex("^v\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)$");
QRegularExpressionMatch matchA = versionRegex.match(QString::fromStdString(a.name));
QRegularExpressionMatch matchB = versionRegex.match(QString::fromStdString(b.name));
if (matchA.hasMatch() && matchB.hasMatch()) {
int majorA = matchA.captured(1).toInt();
int minorA = matchA.captured(2).toInt();
int patchA = matchA.captured(3).toInt();
int majorB = matchB.captured(1).toInt();
int minorB = matchB.captured(2).toInt();
int patchB = matchB.captured(3).toInt();
if (majorA != majorB)
return majorA > majorB;
if (minorA != minorB)
return minorA > minorB;
return patchA > patchB;
}
}
return QString::fromStdString(a.name).compare(QString::fromStdString(b.name),
Qt::CaseInsensitive) < 0;
});
if (versions.empty()) {
ui->versionComboBox->addItem(tr("None"));
ui->versionComboBox->setCurrentIndex(0);
return;
}
for (const auto& v : versions) {
ui->versionComboBox->addItem(QString::fromStdString(v.name),
QString::fromStdString(v.path));
}
int selectedIndex = ui->versionComboBox->findData(savedVersionPath);
if (selectedIndex >= 0) {
ui->versionComboBox->setCurrentIndex(selectedIndex);
} else if (ui->versionComboBox->count() > 0) {
} else {
ui->versionComboBox->setCurrentIndex(0);
selectedIndex = 0;
}
connect(ui->versionComboBox, QOverload<int>::of(&QComboBox::activated), this,
@@ -1453,6 +1500,5 @@ void MainWindow::LoadVersionComboBox() {
m_gui_settings->SetValue(gui::vm_versionSelected, fullPath);
});
ui->versionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
ui->versionComboBox->adjustSize();
}

View File

@@ -94,11 +94,11 @@ VersionDialog::VersionDialog(std::shared_ptr<gui_settings> gui_settings, QWidget
exePath = QFileDialog::getOpenFileName(this, tr("Select executable"), QDir::rootPath(),
tr("Executable (*.exe)"));
#elif defined(Q_OS_LINUX)
exePath = QFileDialog::getOpenFileName(this, tr("Select executable"), QDir::rootPath(),
"Executable (*)");
exePath = QFileDialog::getOpenFileName(this, tr("Select executable"), QDir::rootPath(),
"Executable (*)");
#elif defined(Q_OS_MACOS)
exePath = QFileDialog::getOpenFileName(this, tr("Select executable"), QDir::rootPath(),
"Executable (*.*)");
exePath = QFileDialog::getOpenFileName(this, tr("Select executable"), QDir::rootPath(),
"Executable (*.*)");
#endif
if (exePath.isEmpty())
@@ -114,6 +114,15 @@ VersionDialog::VersionDialog(std::shared_ptr<gui_settings> gui_settings, QWidget
version_name = version_name.trimmed();
if (version_name.startsWith("Pre-release", Qt::CaseInsensitive) ||
version_name.startsWith("Pre-release-shadPS4", Qt::CaseInsensitive)) {
QMessageBox::warning(this, tr("Error"),
// clang-format off
tr("It is not possible to create a version with a name that starts with:\n'Pre-release' or 'Pre-release-shadPS4'."));
// clang-format on
return;
}
if (std::find_if(version_list.cbegin(), version_list.cend(), [version_name](auto i) {
return i.name == version_name.toStdString();
}) != version_list.cend()) {
@@ -124,8 +133,8 @@ VersionDialog::VersionDialog(std::shared_ptr<gui_settings> gui_settings, QWidget
VersionManager::Version new_version = {
.name = version_name.toStdString(),
.path = exePath.toStdString(),
.date = QDateTime::currentDateTime().toString("yyyy.MM.dd. HH:mm").toStdString(),
.codename = "",
.date = QDateTime::currentDateTime().toString("yyyy-MM-dd").toStdString(),
.codename = tr("Local").toStdString(),
.type = VersionManager::VersionType::Custom,
};
VersionManager::AddNewVersion(new_version);
@@ -144,21 +153,63 @@ VersionDialog::VersionDialog(std::shared_ptr<gui_settings> gui_settings, QWidget
return;
}
// Get the actual path of the invisible column folder
QString versionName = selectedItem->text(1);
QString fullPath = selectedItem->text(4);
if (fullPath.isEmpty()) {
QMessageBox::critical(this, tr("Error"), tr("Failed to determine the folder path."));
return;
}
auto reply = QMessageBox::question(this, tr("Delete version"),
tr("Do you want to delete the version") +
QString(" \"%1\" ?").arg(selectedItem->text(1)),
QString(" \"%1\" ?").arg(versionName),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
// not removing any files, as that might be a problem with local ones
VersionManager::RemoveVersion(selectedItem->text(1).toStdString());
LoadInstalledList();
if (reply == QMessageBox::No)
return;
// Check if it is of type Local (type == 2)
auto versions = VersionManager::GetVersionList({});
int versionType = 2;
for (const auto& v : versions) {
if (v.name == versionName.toStdString()) {
versionType = static_cast<int>(v.type);
break;
}
}
if (versionType == 2) {
VersionManager::RemoveVersion(versionName.toStdString());
LoadInstalledList();
return;
}
QFileInfo info(fullPath);
QString folderPath;
if (info.exists() && info.isDir()) {
folderPath = info.absoluteFilePath();
} else {
folderPath = info.absolutePath();
}
if (folderPath.isEmpty()) {
QMessageBox::critical(this, tr("Error"),
tr("Failed to determine the folder to remove.") +
QString("\n \"%1\"").arg(fullPath));
return;
}
QDir dirToRemove(folderPath);
if (dirToRemove.exists()) {
if (!dirToRemove.removeRecursively()) {
QMessageBox::critical(this, tr("Error"),
tr("Failed to delete folder.") +
QString("\n \"%1\"").arg(folderPath));
return;
}
}
VersionManager::RemoveVersion(versionName.toStdString());
LoadInstalledList();
});
connect(ui->checkVersionDownloadButton, &QPushButton::clicked, this,
@@ -309,6 +360,7 @@ void VersionDialog::DownloadListVersion() {
}
void VersionDialog::InstallSelectedVersion() {
disconnect(ui->downloadTreeWidget, &QTreeWidget::itemClicked, nullptr, nullptr);
connect(
ui->downloadTreeWidget, &QTreeWidget::itemClicked, this,
[this](QTreeWidgetItem* item, int) {
@@ -530,13 +582,25 @@ tr("First you need to choose a location to save the versions in\n'Path to save v
this, tr("Confirm Download"),
tr("Version %1 has been downloaded and selected.")
.arg(versionName));
bool is_release = !versionName.contains("Pre-release");
auto release_name = release["name"].toString();
QString code_name = "";
static constexpr QStringView marker = u" - codename ";
int idx = release_name.indexOf(u" - codename ");
if (idx != -1) {
code_name = release_name.mid(idx + marker.size());
if (is_release) {
static constexpr QStringView marker = u" - codename ";
int idx = release_name.indexOf(marker);
if (idx != -1)
code_name = release_name.mid(idx + marker.size());
} else {
QRegularExpression re("-([a-fA-F0-9]{7,})$");
QRegularExpressionMatch match = re.match(folderName);
if (match.hasMatch()) {
QString fullHash = match.captured(1);
code_name = fullHash.left(7);
} else {
code_name = "unknown";
}
}
std::filesystem::path exe_path =
Common::FS::PathFromQString(executablePath);
@@ -551,8 +615,9 @@ tr("First you need to choose a location to save the versions in\n'Path to save v
.type = is_release ? VersionManager::VersionType::Release
: VersionManager::VersionType::Nightly,
};
m_gui_settings->SetValue(gui::vm_versionSelected,
QString(exe_path.c_str()));
m_gui_settings->SetValue(
gui::vm_versionSelected,
QString::fromStdString(new_version.path));
VersionManager::AddNewVersion(new_version);
LoadInstalledList();
});
@@ -570,14 +635,59 @@ tr("First you need to choose a location to save the versions in\n'Path to save v
void VersionDialog::LoadInstalledList() {
const auto path = Common::FS::GetUserPath(Common::FS::PathType::LauncherDir) / "versions.json";
auto versions = VersionManager::GetVersionList(path);
auto const& selected_version =
const auto& selected_version =
m_gui_settings->GetValue(gui::vm_versionSelected).toString().toStdString();
std::sort(versions.begin(), versions.end(), [](const auto& a, const auto& b) {
auto getOrder = [](int type) {
switch (type) {
case 1: // Pre-release
return 0;
case 0: // Release
return 1;
case 2: // Local
return 2;
default:
return 3;
}
};
int orderA = getOrder(static_cast<int>(a.type));
int orderB = getOrder(static_cast<int>(b.type));
if (orderA != orderB)
return orderA < orderB;
if (a.type == VersionManager::VersionType::Release) {
static QRegularExpression versionRegex("^v\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)$");
QRegularExpressionMatch matchA = versionRegex.match(QString::fromStdString(a.name));
QRegularExpressionMatch matchB = versionRegex.match(QString::fromStdString(b.name));
if (matchA.hasMatch() && matchB.hasMatch()) {
int majorA = matchA.captured(1).toInt();
int minorA = matchA.captured(2).toInt();
int patchA = matchA.captured(3).toInt();
int majorB = matchB.captured(1).toInt();
int minorB = matchB.captured(2).toInt();
int patchB = matchB.captured(3).toInt();
if (majorA != majorB)
return majorA > majorB;
if (minorA != minorB)
return minorA > minorB;
return patchA > patchB;
}
}
return QString::fromStdString(a.name).compare(QString::fromStdString(b.name),
Qt::CaseInsensitive) < 0;
});
ui->installedTreeWidget->clear();
ui->installedTreeWidget->setColumnCount(5);
ui->installedTreeWidget->setColumnHidden(4, true);
for (auto const& v : versions) {
for (const auto& v : versions) {
QTreeWidgetItem* item = new QTreeWidgetItem(ui->installedTreeWidget);
item->setText(1, QString::fromStdString(v.name));
item->setText(2, QString::fromStdString(v.codename));
@@ -721,16 +831,19 @@ void VersionDialog::checkUpdatePre(const bool showMessage) {
}
if (localHash.isEmpty()) {
QMessageBox::StandardButton reply =
QMessageBox::question(this, tr("No pre-release found"),
// clang-format off
tr("You don't have any pre-release installed yet.\nWould you like to download it now?"),
// clang-format on
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
installPreReleaseByTag(latestTag);
auto* tree = ui->downloadTreeWidget;
int topCount = tree->topLevelItemCount();
for (int i = 0; i < topCount; ++i) {
QTreeWidgetItem* item = tree->topLevelItem(i);
if (item && item->text(0).contains("Pre-release", Qt::CaseInsensitive)) {
tree->setCurrentItem(item);
tree->scrollToItem(item);
tree->setFocus();
emit tree->itemClicked(item, 0);
break;
}
}
return;
}
if (latestHash == localHash) {
@@ -748,6 +861,9 @@ void VersionDialog::checkUpdatePre(const bool showMessage) {
void VersionDialog::showPreReleaseUpdateDialog(const QString& localHash, const QString& latestHash,
const QString& latestTag) {
if (localHash == "") {
return;
}
QDialog dialog(this);
dialog.setWindowTitle(tr("Auto Updater - Emulator"));
@@ -1061,13 +1177,22 @@ void VersionDialog::showDownloadDialog(const QString& tagName, const QString& do
return;
}
QString codename;
QRegularExpression re("-([a-fA-F0-9]{7,})$");
QRegularExpressionMatch match = re.match(tagName);
if (match.hasMatch()) {
QString fullHash = match.captured(1);
codename = fullHash.left(7);
} else {
codename = "unknown";
}
auto const exe = m_gui_settings->GetVersionExecutablePath(destFolder);
VersionManager::Version new_version = {
.name = "Pre-release",
.path = exe.toStdString(),
.date =
QDateTime::currentDateTime().toString("yyyy.MM.dd. HH:mm").toStdString(),
.codename = "",
.date = QDateTime::currentDateTime().toString("yyyy-MM-dd").toStdString(),
.codename = codename.toStdString(),
.type = VersionManager::VersionType::Nightly,
};
VersionManager::UpdatePrerelease(new_version);