#include "createinstancedialogpages.h"
#include "filesystemutilities.h"
#include "instancemanager.h"
#include "plugincontainer.h"
#include "settings.h"
#include "settingsdialognexus.h"
#include "shared/appconfig.h"
#include "ui_createinstancedialog.h"
#include <iplugingame.h>
#include <report.h>
#include <utility.h>
namespace cid
{
using namespace MOBase;
using MOBase::TaskDialog;
QString makeDefaultPath(const std::wstring& dir)
{
return QDir::toNativeSeparators(
PathSettings::makeDefaultPath(QString::fromStdWString(dir)));
}
QString toLocalizedString(CreateInstanceDialog::Types t)
{
switch (t) {
case CreateInstanceDialog::Global:
return QObject::tr("Global");
case CreateInstanceDialog::Portable:
return QObject::tr("Portable");
default:
return QObject::tr("Instance type: %1").arg(QObject::tr("?"));
}
}
PlaceholderLabel::PlaceholderLabel(QLabel* label)
: m_label(label), m_original(label->text())
{}
void PlaceholderLabel::setText(const QString& arg)
{
if (m_original.contains("%1")) {
m_label->setText(m_original.arg(arg));
}
}
void PlaceholderLabel::setVisible(bool b)
{
m_label->setVisible(b);
}
Page::Page(CreateInstanceDialog& dlg)
: ui(dlg.getUI()), m_dlg(dlg), m_pc(dlg.pluginContainer()), m_skip(false),
m_firstActivation(true)
{}
bool Page::ready() const
{
return true;
}
bool Page::skip() const
{
return m_skip || doSkip();
}
bool Page::doSkip() const
{
return false;
}
void Page::doActivated(bool)
{
}
void Page::activated()
{
doActivated(m_firstActivation);
m_firstActivation = false;
}
void Page::setSkip(bool b)
{
m_skip = b;
}
void Page::updateNavigation()
{
m_dlg.updateNavigation();
}
void Page::next()
{
m_dlg.next();
}
bool Page::action(CreateInstanceDialog::Actions a)
{
return false;
}
CreateInstanceDialog::Types Page::selectedInstanceType() const
{
return CreateInstanceDialog::NoType;
}
IPluginGame* Page::selectedGame() const
{
return nullptr;
}
QString Page::selectedGameLocation() const
{
return {};
}
QString Page::selectedGameVariant(MOBase::IPluginGame*) const
{
return {};
}
QString Page::selectedInstanceName() const
{
return {};
}
CreateInstanceDialog::Paths Page::selectedPaths() const
{
return {};
}
CreateInstanceDialog::ProfileSettings Page::profileSettings() const
{
return {};
}
IntroPage::IntroPage(CreateInstanceDialog& dlg)
: Page(dlg), m_skip(GlobalSettings::hideCreateInstanceIntro())
{
QObject::connect(ui->hideIntro, &QCheckBox::toggled, [&] {
GlobalSettings::setHideCreateInstanceIntro(ui->hideIntro->isChecked());
});
}
bool IntroPage::doSkip() const
{
return m_skip;
}
TypePage::TypePage(CreateInstanceDialog& dlg)
: Page(dlg), m_type(CreateInstanceDialog::NoType)
{
ui->createGlobal->setDescription(ui->createGlobal->description().arg(
InstanceManager::singleton().globalInstancesRootPath()));
ui->createPortable->setDescription(ui->createPortable->description().arg(
InstanceManager::singleton().portablePath()));
if (InstanceManager::singleton().portableInstanceExists()) {
ui->createPortable->setEnabled(false);
ui->portableExistsLabel->setVisible(true);
} else {
ui->createPortable->setEnabled(true);
ui->portableExistsLabel->setVisible(false);
}
QObject::connect(ui->createGlobal, &QAbstractButton::clicked, [&] {
global();
});
QObject::connect(ui->createPortable, &QAbstractButton::clicked, [&] {
portable();
});
}
bool TypePage::ready() const
{
return (m_type != CreateInstanceDialog::NoType);
}
CreateInstanceDialog::Types TypePage::selectedInstanceType() const
{
return m_type;
}
void TypePage::global()
{
m_type = CreateInstanceDialog::Global;
ui->createGlobal->setChecked(true);
ui->createPortable->setChecked(false);
next();
}
void TypePage::portable()
{
m_type = CreateInstanceDialog::Portable;
ui->createGlobal->setChecked(false);
ui->createPortable->setChecked(true);
next();
}
void TypePage::doActivated(bool firstTime)
{
if (firstTime) {
ui->createGlobal->setFocus();
}
}
GamePage::Game::Game(IPluginGame* g) : game(g), installed(g->isInstalled())
{
if (installed) {
dir = game->gameDirectory().path();
}
}
GamePage::GamePage(CreateInstanceDialog& dlg) : Page(dlg), m_selection(nullptr)
{
createGames();
fillList();
m_filter.setEdit(ui->gamesFilter);
QObject::connect(&m_filter, &FilterWidget::changed, [&] {
fillList();
});
QObject::connect(ui->showAllGames, &QCheckBox::clicked, [&] {
fillList();
});
}
bool GamePage::ready() const
{
return (m_selection != nullptr);
}
bool GamePage::action(CreateInstanceDialog::Actions a)
{
using Actions = CreateInstanceDialog::Actions;
if (a == Actions::Find) {
ui->gamesFilter->setFocus();
return true;
}
return false;
}
IPluginGame* GamePage::selectedGame() const
{
if (!m_selection) {
return nullptr;
}
return m_selection->game;
}
QString GamePage::selectedGameLocation() const
{
if (!m_selection) {
return {};
}
return QDir::toNativeSeparators(m_selection->dir);
}
void GamePage::select(IPluginGame* game, const QString& dir)
{
Game* checked = findGame(game);
if (checked) {
if (!checked->installed || (detectMicrosoftStore(checked->dir) &&
!confirmMicrosoftStore(checked->dir, checked->game))) {
if (dir.isEmpty()) {
const auto path = QFileDialog::getExistingDirectory(
&m_dlg,
QObject::tr("Find game installation for %1").arg(game->displayGameName()));
if (path.isEmpty()) {
checked = nullptr;
} else if (detectMicrosoftStore(path) && !confirmMicrosoftStore(path, game)) {
checked = nullptr;
} else {
checked = checkInstallation(path, checked);
if (checked) {
checked->dir = path;
checked->installed = true;
}
}
} else {
checked->dir = dir;
checked->installed = true;
}
}
}
m_selection = checked;
updateButton(checked);
selectButton(checked);
updateNavigation();
if (checked) {
next();
}
}
void GamePage::selectCustom()
{
const auto path =
QFileDialog::getExistingDirectory(&m_dlg, QObject::tr("Find game installation"));
if (path.isEmpty()) {
selectButton(m_selection);
return;
}
if (detectMicrosoftStore(path) && !confirmMicrosoftStore(path, nullptr)) {
selectButton(m_selection);
return;
}
for (auto& g : m_games) {
if (g->game->looksValid(path)) {
g->dir = path;
g->installed = true;
select(g->game);
updateButton(g.get());
return;
}
}
warnUnrecognized(path);
selectButton(m_selection);
}
void GamePage::warnUnrecognized(const QString& path)
{
QString supportedGames;
for (auto* game : sortedGamePlugins()) {
supportedGames += game->displayGameName() + "\n";
}
QMessageBox dlg(&m_dlg);
dlg.setWindowTitle(QObject::tr("Unrecognized game"));
dlg.setText(
QObject::tr("The folder %1 does not seem to contain a game Mod Organizer can "
"manage.")
.arg(path));
dlg.setInformativeText(QObject::tr("See details for the list of supported games."));
dlg.setDetailedText(supportedGames);
dlg.setIcon(QMessageBox::Warning);
dlg.setStandardButtons(QMessageBox::Ok);
dlg.exec();
}
std::vector<IPluginGame*> GamePage::sortedGamePlugins() const
{
std::vector<IPluginGame*> v;
for (auto* game : m_pc.plugins<IPluginGame>()) {
v.push_back(game);
}
std::sort(v.begin(), v.end(), [](auto* a, auto* b) {
return (naturalCompare(a->displayGameName(), b->displayGameName()) < 0);
});
return v;
}
void GamePage::createGames()
{
m_games.clear();
for (auto* game : sortedGamePlugins()) {
m_games.push_back(std::make_unique<Game>(game));
}
}
GamePage::Game* GamePage::findGame(IPluginGame* game)
{
for (auto& g : m_games) {
if (g->game == game) {
return g.get();
}
}
return nullptr;
}
void GamePage::createGameButton(Game* g)
{
g->button = new QCommandLinkButton;
g->button->setCheckable(true);
updateButton(g);
QObject::connect(g->button, &QAbstractButton::clicked, [g, this] {
select(g->game);
});
}
void GamePage::addButton(QAbstractButton* b)
{
auto* ly = static_cast<QVBoxLayout*>(ui->games->layout());
ly->insertWidget(ly->count() - 1, b);
}
void GamePage::updateButton(Game* g)
{
if (!g || !g->button) {
return;
}
g->button->setText(g->game->displayGameName().replace("&", "&&"));
g->button->setIcon(g->game->gameIcon());
if (g->installed) {
g->button->setDescription(g->dir);
} else {
g->button->setDescription(QObject::tr("No installation found"));
}
}
void GamePage::selectButton(Game* g)
{
for (const auto& gg : m_games) {
if (!g) {
if (gg->button) {
gg->button->setChecked(false);
}
continue;
}
if (gg->game == g->game) {
if (!gg->button) {
createGameButton(gg.get());
addButton(gg->button);
}
gg->button->setChecked(true);
gg->button->setFocus();
} else {
if (gg->button) {
gg->button->setChecked(false);
}
}
}
}
void GamePage::clearButtons()
{
auto* ly = static_cast<QVBoxLayout*>(ui->games->layout());
ui->games->setUpdatesEnabled(false);
qDeleteAll(ui->games->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
while (auto* child = ly->takeAt(0))
delete child;
ly->addStretch();
ui->games->setUpdatesEnabled(true);
for (auto& g : m_games) {
g->button = nullptr;
}
}
QCommandLinkButton* GamePage::createCustomButton()
{
auto* b = new QCommandLinkButton;
b->setText(QObject::tr("Browse..."));
b->setDescription(QObject::tr("The folder must contain a valid game installation"));
QObject::connect(b, &QAbstractButton::clicked, [&] {
selectCustom();
});
return b;
}
void GamePage::fillList()
{
const bool showAll = ui->showAllGames->isChecked();
clearButtons();
Game* firstButton = nullptr;
for (auto& g : m_games) {
if (!showAll && !g->installed) {
continue;
}
if (!m_filter.matches(g->game->gameName()) &&
!m_filter.matches(g->game->displayGameName())) {
continue;
}
createGameButton(g.get());
addButton(g->button);
if (!firstButton) {
firstButton = g.get();
}
}
addButton(createCustomButton());
if (firstButton) {
firstButton->button->setDefault(true);
}
}
GamePage::Game* GamePage::checkInstallation(const QString& path, Game* g)
{
if (g->game->looksValid(path)) {
return g;
}
if (detectMicrosoftStore(path) && confirmMicrosoftStore(path, g->game)) {
return g;
}
IPluginGame* otherGame = nullptr;
for (auto* gg : m_pc.plugins<IPluginGame>()) {
if (gg->looksValid(path)) {
otherGame = gg;
break;
}
}
if (otherGame == g->game) {
return g;
}
if (otherGame) {
auto* confirmedGame = confirmOtherGame(path, g->game, otherGame);
if (!confirmedGame) {
return nullptr;
}
g = findGame(confirmedGame);
if (!g) {
return nullptr;
}
} else {
if (!confirmUnknown(path, g->game)) {
return nullptr;
}
}
g->dir = path;
g->installed = true;
updateButton(g);
return g;
}
bool GamePage::detectMicrosoftStore(const QString& path)
{
return path.contains("/ModifiableWindowsApps/") || path.contains("/WindowsApps/");
}
bool GamePage::confirmMicrosoftStore(const QString& path, IPluginGame* game)
{
const auto r =
TaskDialog(&m_dlg)
.title(QObject::tr("Microsoft Store game"))
.main(QObject::tr("Microsoft Store game"))
.content(
QObject::tr(
"The folder %1 seems to be a Microsoft Store game install. Games"
" installed through the Microsoft Store are not supported by Mod "
"Organizer"
" and will not work properly.")
.arg(path))
.button(
{game ? QObject::tr("Use this folder for %1").arg(game->displayGameName())
: QObject::tr("Use this folder"),
QObject::tr("I know what I'm doing"), QMessageBox::Ignore})
.button({QObject::tr("Cancel"), QMessageBox::Cancel})
.exec();
return (r == QMessageBox::Ignore);
}
bool GamePage::confirmUnknown(const QString& path, IPluginGame* game)
{
const auto r =
TaskDialog(&m_dlg)
.title(QObject::tr("Unrecognized game"))
.main(QObject::tr("Unrecognized game"))
.content(
QObject::tr("The folder %1 does not seem to contain an installation for "
"<span style=\"white-space: nowrap; font-weight: "
"bold;\">%2</span> or "
"for any other game Mod Organizer can manage.")
.arg(path)
.arg(game->displayGameName()))
.button({QObject::tr("Use this folder for %1").arg(game->displayGameName()),
QObject::tr("I know what I'm doing"), QMessageBox::Ignore})
.button({QObject::tr("Cancel"), QMessageBox::Cancel})
.exec();
return (r == QMessageBox::Ignore);
}
IPluginGame* GamePage::confirmOtherGame(const QString& path, IPluginGame* selectedGame,
IPluginGame* guessedGame)
{
const auto r =
TaskDialog(&m_dlg)
.title(QObject::tr("Incorrect game"))
.main(QObject::tr("Incorrect game"))
.content(
QObject::tr(
"The folder %1 seems to contain an installation for "
"<span style=\"white-space: nowrap; font-weight: bold;\">%2</span>, "
"not "
"<span style=\"white-space: nowrap; font-weight: bold;\">%3</span>.")
.arg(path)
.arg(guessedGame->displayGameName())
.arg(selectedGame->displayGameName()))
.button({QObject::tr("Manage %1 instead").arg(guessedGame->displayGameName()),
QMessageBox::Ok})
.button({QObject::tr("Use this folder for %1")
.arg(selectedGame->displayGameName()),
QObject::tr("I know what I'm doing"), QMessageBox::Ignore})
.button({QObject::tr("Cancel"), QMessageBox::Cancel})
.exec();
switch (r) {
case QMessageBox::Ok:
return guessedGame;
case QMessageBox::Ignore:
return selectedGame;
case QMessageBox::Cancel:
default:
return nullptr;
}
}
VariantsPage::VariantsPage(CreateInstanceDialog& dlg)
: Page(dlg), m_previousGame(nullptr)
{}
bool VariantsPage::ready() const
{
return !m_selection.isEmpty();
}
bool VariantsPage::doSkip() const
{
auto* g = m_dlg.rawCreationInfo().game;
if (!g) {
return true;
}
return (g->gameVariants().size() < 2);
}
void VariantsPage::doActivated(bool)
{
auto* g = m_dlg.rawCreationInfo().game;
if (m_previousGame != g) {
m_previousGame = g;
m_selection = "";
fillList();
}
}
void VariantsPage::select(const QString& variant)
{
m_selection = variant;
for (auto* b : m_buttons) {
if (b->text() == variant) {
b->setChecked(true);
} else {
b->setChecked(false);
}
}
updateNavigation();
if (!m_selection.isEmpty()) {
next();
}
}
QString VariantsPage::selectedGameVariant(MOBase::IPluginGame* game) const
{
if (!game) {
return {};
}
if (game->gameVariants().size() < 2) {
return {};
} else {
return m_selection;
}
}
void VariantsPage::fillList()
{
ui->editions->clear();
m_buttons.clear();
auto* g = m_dlg.rawCreationInfo().game;
if (!g) {
return;
}
for (auto& v : g->gameVariants()) {
auto* b = new QCommandLinkButton(v);
b->setCheckable(true);
QObject::connect(b, &QAbstractButton::clicked, [v, this] {
select(v);
});
ui->editions->addButton(b, QDialogButtonBox::AcceptRole);
m_buttons.push_back(b);
}
if (!m_buttons.empty()) {
m_buttons[0]->setDefault(true);
}
}
NamePage::NamePage(CreateInstanceDialog& dlg)
: Page(dlg), m_modified(false), m_okay(false), m_label(ui->instanceNameLabel),
m_exists(ui->instanceNameExists), m_invalid(ui->instanceNameInvalid)
{
QObject::connect(ui->instanceName, &QLineEdit::textEdited, [&] {
onChanged();
});
QObject::connect(ui->instanceName, &QLineEdit::returnPressed, [&] {
next();
});
}
bool NamePage::ready() const
{
return m_okay;
}
bool NamePage::doSkip() const
{
return (m_dlg.rawCreationInfo().type == CreateInstanceDialog::Portable);
}
void NamePage::doActivated(bool)
{
auto* g = m_dlg.rawCreationInfo().game;
if (!g) {
return;
}
m_label.setText(g->gameName());
if (!m_modified || ui->instanceName->text().isEmpty()) {
const auto n = InstanceManager::singleton().makeUniqueName(g->gameName());
ui->instanceName->setText(n);
m_modified = false;
}
verify();
}
QString NamePage::selectedInstanceName() const
{
if (!m_okay) {
return {};
}
const auto text = ui->instanceName->text().trimmed();
return MOBase::sanitizeFileName(text);
}
void NamePage::onChanged()
{
m_modified = true;
verify();
}
void NamePage::verify()
{
const auto root = InstanceManager::singleton().globalInstancesRootPath();
m_okay = checkName(root, ui->instanceName->text());
updateNavigation();
}
bool NamePage::checkName(QString parentDir, QString name)
{
bool exists = false;
bool invalid = false;
bool empty = false;
name = name.trimmed();
if (name.isEmpty()) {
empty = true;
} else {
if (MOBase::validFileName(name)) {
exists = QDir(parentDir).exists(name);
} else {
invalid = true;
}
}
bool okay = false;
if (exists) {
m_exists.setVisible(true);
m_exists.setText(QDir(parentDir).filePath(name));
m_invalid.setVisible(false);
} else if (invalid) {
m_exists.setVisible(false);
m_invalid.setVisible(true);
m_invalid.setText(name);
} else {
okay = !empty;
m_exists.setVisible(false);
m_invalid.setVisible(false);
}
return okay;
}
ProfilePage::ProfilePage(CreateInstanceDialog& dlg) : Page(dlg) {}
bool ProfilePage::ready() const
{
return true;
}
CreateInstanceDialog::ProfileSettings ProfilePage::profileSettings() const
{
CreateInstanceDialog::ProfileSettings profileSettings;
profileSettings.localInis = ui->profileInisCheckbox->isChecked();
profileSettings.localSaves = ui->profileSavesCheckbox->isChecked();
profileSettings.archiveInvalidation = ui->archiveInvalidationCheckbox->isChecked();
return profileSettings;
}
PathsPage::PathsPage(CreateInstanceDialog& dlg)
: Page(dlg), m_lastType(CreateInstanceDialog::NoType), m_label(ui->pathsLabel),
m_simpleExists(ui->locationExists), m_simpleInvalid(ui->locationInvalid),
m_advancedExists(ui->advancedDirExists),
m_advancedInvalid(ui->advancedDirInvalid), m_okay(false)
{
auto setEdit = [&](QLineEdit* e) {
QObject::connect(e, &QLineEdit::textEdited, [&] {
onChanged();
});
QObject::connect(e, &QLineEdit::returnPressed, [&] {
next();
});
};
auto setBrowse = [&](QAbstractButton* b, QLineEdit* e) {
QObject::connect(b, &QAbstractButton::clicked, [this, e] {
browse(e);
});
};
setEdit(ui->location);
setEdit(ui->base);
setEdit(ui->downloads);
setEdit(ui->mods);
setEdit(ui->profiles);
setEdit(ui->overwrite);
setBrowse(ui->browseLocation, ui->location);
setBrowse(ui->browseBase, ui->base);
setBrowse(ui->browseDownloads, ui->downloads);
setBrowse(ui->browseMods, ui->mods);
setBrowse(ui->browseProfiles, ui->profiles);
setBrowse(ui->browseOverwrite, ui->overwrite);
QObject::connect(ui->advancedPathOptions, &QCheckBox::clicked, [&] {
onAdvanced();
});
ui->pathPages->setCurrentIndex(0);
}
bool PathsPage::ready() const
{
return m_okay;
}
void PathsPage::doActivated(bool firstTime)
{
const auto name = m_dlg.rawCreationInfo().instanceName;
const auto type = m_dlg.rawCreationInfo().type;
const bool changed = (m_lastInstanceName != name) || (m_lastType != type);
setPaths(name, changed);
checkPaths();
updateNavigation();
m_label.setText(m_dlg.rawCreationInfo().game->gameName());
m_lastInstanceName = name;
m_lastType = type;
if (firstTime) {
ui->location->setFocus();
}
}
CreateInstanceDialog::Paths PathsPage::selectedPaths() const
{
CreateInstanceDialog::Paths p;
if (ui->advancedPathOptions->isChecked()) {
p.base = ui->base->text();
p.downloads = ui->downloads->text();
p.mods = ui->mods->text();
p.profiles = ui->profiles->text();
p.overwrite = ui->overwrite->text();
} else {
p.base = ui->location->text();
}
return p;
}
void PathsPage::onChanged()
{
checkPaths();
updateNavigation();
}
void PathsPage::browse(QLineEdit* e)
{
const auto s = QFileDialog::getExistingDirectory(&m_dlg, {}, e->text());
if (s.isNull() || s.isEmpty()) {
return;
}
e->setText(QDir::toNativeSeparators(s));
}
void PathsPage::checkPaths()
{
if (ui->advancedPathOptions->isChecked()) {
m_okay = checkAdvancedPath(ui->base->text()) &&
checkAdvancedPath(resolve(ui->downloads->text())) &&
checkAdvancedPath(resolve(ui->mods->text())) &&
checkAdvancedPath(resolve(ui->profiles->text())) &&
checkAdvancedPath(resolve(ui->overwrite->text()));
} else {
m_okay = checkSimplePath(ui->location->text());
}
}
bool PathsPage::checkSimplePath(const QString& path)
{
return checkPath(path, m_simpleExists, m_simpleInvalid);
}
bool PathsPage::checkAdvancedPath(const QString& path)
{
return checkPath(path, m_advancedExists, m_advancedInvalid);
}
QString PathsPage::resolve(const QString& path) const
{
return PathSettings::resolve(path, ui->base->text());
}
void PathsPage::onAdvanced()
{
if (ui->advancedPathOptions->isChecked()) {
ui->base->setText(ui->location->text());
ui->pathPages->setCurrentIndex(1);
} else {
ui->location->setText(ui->base->text());
ui->pathPages->setCurrentIndex(0);
}
checkPaths();
}
void PathsPage::setPaths(const QString& name, bool force)
{
QString basePath;
if (m_dlg.rawCreationInfo().type == CreateInstanceDialog::Portable) {
basePath = InstanceManager::singleton().portablePath();
} else {
const auto root = InstanceManager::singleton().globalInstancesRootPath();
basePath = root + "/" + name;
}
basePath = QDir::toNativeSeparators(QDir::cleanPath(basePath));
setIfEmpty(ui->location, basePath, force);
setIfEmpty(ui->base, basePath, force);
setIfEmpty(ui->downloads, makeDefaultPath(AppConfig::downloadPath()), force);
setIfEmpty(ui->mods, makeDefaultPath(AppConfig::modsPath()), force);
setIfEmpty(ui->profiles, makeDefaultPath(AppConfig::profilesPath()), force);
setIfEmpty(ui->overwrite, makeDefaultPath(AppConfig::overwritePath()), force);
}
void PathsPage::setIfEmpty(QLineEdit* e, const QString& path, bool force)
{
if (e->text().isEmpty() || force) {
e->setText(path);
}
}
bool PathsPage::checkPath(QString path, PlaceholderLabel& existsLabel,
PlaceholderLabel& invalidLabel)
{
auto& m = InstanceManager::singleton();
bool exists = false;
bool invalid = false;
bool empty = false;
path = QDir::toNativeSeparators(path.trimmed());
if (path.isEmpty()) {
empty = true;
} else {
const QDir d(path);
if (MOBase::validFileName(d.dirName())) {
if (m_dlg.rawCreationInfo().type == CreateInstanceDialog::Portable) {
if (QDir(path) != m.portablePath()) {
exists = QDir(path).exists();
}
} else {
exists = QDir(path).exists();
}
} else {
invalid = true;
}
}
bool okay = true;
if (invalid) {
okay = false;
existsLabel.setVisible(false);
invalidLabel.setVisible(true);
invalidLabel.setText(path);
} else if (empty) {
okay = false;
existsLabel.setVisible(false);
invalidLabel.setVisible(false);
} else if (exists) {
existsLabel.setVisible(true);
existsLabel.setText(path);
invalidLabel.setVisible(false);
} else {
okay = true;
existsLabel.setVisible(false);
invalidLabel.setVisible(false);
}
return okay;
}
NexusPage::NexusPage(CreateInstanceDialog& dlg) : Page(dlg), m_skip(false)
{
m_connectionUI.reset(new NexusConnectionUI(&m_dlg, dlg.settings(), ui->nexusConnect,
nullptr, ui->nexusManual, ui->nexusLog));
m_skip = GlobalSettings::hasNexusApiKey();
}
NexusPage::~NexusPage() = default;
bool NexusPage::ready() const
{
return true;
}
bool NexusPage::doSkip() const
{
return m_skip;
}
ConfirmationPage::ConfirmationPage(CreateInstanceDialog& dlg) : Page(dlg) {}
void ConfirmationPage::doActivated(bool)
{
ui->review->setPlainText(makeReview());
ui->creationLog->clear();
}
QString ConfirmationPage::makeReview() const
{
QStringList lines;
const auto ci = m_dlg.rawCreationInfo();
lines.push_back(QObject::tr("Instance type: %1").arg(toLocalizedString(ci.type)));
lines.push_back(QObject::tr("Instance location: %1").arg(ci.dataPath));
if (ci.type != CreateInstanceDialog::Portable) {
lines.push_back(QObject::tr("Instance name: %1").arg(ci.instanceName));
}
lines.push_back(QObject::tr("Profile settings:"));
lines.push_back(
QObject::tr(" Local INIs: %1")
.arg(ci.profileSettings.localInis ? QObject::tr("yes") : QObject::tr("no")));
lines.push_back(
QObject::tr(" Local Saves: %1")
.arg(ci.profileSettings.localSaves ? QObject::tr("yes") : QObject::tr("no")));
lines.push_back(QObject::tr(" Automatic Archive Invalidation: %1")
.arg(ci.profileSettings.archiveInvalidation ? QObject::tr("yes")
: QObject::tr("no")));
if (ci.paths.downloads.isEmpty()) {
if (ci.paths.base != ci.dataPath) {
lines.push_back(QObject::tr("Base directory: %1").arg(ci.paths.base));
}
} else {
lines.push_back(QObject::tr("Base directory: %1").arg(ci.paths.base));
lines.push_back(dirLine(QObject::tr("Downloads"), ci.paths.downloads));
lines.push_back(dirLine(QObject::tr("Mods"), ci.paths.mods));
lines.push_back(dirLine(QObject::tr("Profiles"), ci.paths.profiles));
lines.push_back(dirLine(QObject::tr("Overwrite"), ci.paths.overwrite));
}
QString name = ci.game->gameName();
if (!ci.gameVariant.isEmpty()) {
name += " (" + ci.gameVariant + ")";
}
lines.push_back(QObject::tr("Game: %1").arg(name));
lines.push_back(QObject::tr("Game location: %1").arg(ci.gameLocation));
return lines.join("\n");
}
QString ConfirmationPage::dirLine(const QString& caption, const QString& path) const
{
return QString(" - %1: %2").arg(caption).arg(path);
}
}