Skip to content

Commit

Permalink
Add a method to use existing game installations from other launchers
Browse files Browse the repository at this point in the history
This should work for XIVLauncher.Core, XIVQuickLauncher and the official
launcher. More testing is needed of course, but the framework is there
now.
  • Loading branch information
redstrate committed May 26, 2024
1 parent 42a135e commit 4948db8
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 14 deletions.
2 changes: 1 addition & 1 deletion external/libphysis
2 changes: 2 additions & 0 deletions launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ target_sources(astra PRIVATE
include/benchmarkinstaller.h
include/compatibilitytoolinstaller.h
include/encryptedarg.h
include/existinginstallmodel.h
include/gamerunner.h
include/gameinstaller.h
include/headline.h
Expand All @@ -68,6 +69,7 @@ target_sources(astra PRIVATE
src/benchmarkinstaller.cpp
src/compatibilitytoolinstaller.cpp
src/encryptedarg.cpp
src/existinginstallmodel.cpp
src/gamerunner.cpp
src/headline.cpp
src/gameinstaller.cpp
Expand Down
35 changes: 35 additions & 0 deletions launcher/include/existinginstallmodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <QtQml>
#include <physis.hpp>

class ExistingInstallModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT

public:
enum CustomRoles {
TypeRole = Qt::UserRole,
PathRole,
};

explicit ExistingInstallModel(QObject *parent = nullptr);

QVariant data(const QModelIndex &index, int role) const override;
int rowCount(const QModelIndex &parent) const override;
QHash<int, QByteArray> roleNames() const override;

private:
void fill();

struct ExistingInstall {
ExistingInstallType type;
QString path;
};

QList<ExistingInstall> m_existingInstalls;
};
68 changes: 68 additions & 0 deletions launcher/src/existinginstallmodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "existinginstallmodel.h"

#include <KLocalizedString>

ExistingInstallModel::ExistingInstallModel(QObject *parent)
: QAbstractListModel(parent)
{
fill();
}

QVariant ExistingInstallModel::data(const QModelIndex &index, int role) const
{
Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid));

const auto &install = m_existingInstalls[index.row()];

switch (role) {
case TypeRole: {
switch (install.type) {
case ExistingInstallType::OfficialLauncher:
return i18n("Official Launcher");
case ExistingInstallType::XIVLauncherCore:
return QStringLiteral("XIVLauncher.Core");
case ExistingInstallType::XIVOnMac:
return QStringLiteral("XIV on Mac");
case ExistingInstallType::XIVQuickLauncher:
return QStringLiteral("XIVQuickLauncher");
default:
return i18n("Unknown");
}
}
case PathRole:
return install.path;
default:
return {};
}
}

int ExistingInstallModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_existingInstalls.size();
}

QHash<int, QByteArray> ExistingInstallModel::roleNames() const
{
return {
{TypeRole, "type"},
{PathRole, "path"},
};
}

void ExistingInstallModel::fill()
{
auto dirs = physis_find_existing_game_dirs();
for (int i = 0; i < dirs.count; i++) {
// We shouldn't be able to import our own game installs, that's handled elsewhere in the UI
if (dirs.entries[i].install_type != ExistingInstallType::Astra) {
beginInsertRows({}, m_existingInstalls.size(), m_existingInstalls.size());
m_existingInstalls.push_back(ExistingInstall{.type = dirs.entries[i].install_type, .path = QString::fromUtf8(dirs.entries[i].path)});
endInsertRows();
}
}
}

#include "moc_existinginstallmodel.cpp"
48 changes: 35 additions & 13 deletions launcher/ui/Setup/ExistingSetup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,58 @@ FormCard.FormCardPage {

title: i18n("Find Existing Installation")

data: FolderDialog {
id: dialog

onAccepted: {
page.profile.gamePath = decodeURIComponent(selectedFolder.toString().replace("file://", ""));
applicationWindow().checkSetup();
}
}

FormCard.FormCard {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.largeSpacing

Repeater {
model: ExistingInstallModel {}

delegate: FormCard.FormButtonDelegate {
required property var path
required property var type

text: path
description: type

onClicked: {
page.profile.gamePath = path;
applicationWindow().checkSetup();
}
}
}
}

FormCard.FormCard {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.largeSpacing

FormCard.FormTextDelegate {
id: helpTextDelegate

text: i18n("Please select the path to your existing installation.")
text: i18n("If you can't find your existing game installation, manually select the path below.")
}

FormCard.FormDelegateSeparator {
above: helpTextDelegate
below: selectDelegate
}

FormCard.FormButtonDelegate {
id: selectDelegate

text: i18n("Select Existing Path")
icon.name: "document-open-folder"
text: i18n("Select Existing Path")

onClicked: dialog.open()
}
}
}

data: FolderDialog {
id: dialog

onAccepted: {
page.profile.gamePath = decodeURIComponent(selectedFolder.toString().replace("file://", ""));
applicationWindow().checkSetup();
}
}
}

0 comments on commit 4948db8

Please sign in to comment.