mirror of
https://github.com/OpenMW/openmw.git
synced 2026-06-29 00:59:03 -04:00
b370bce480
This turned out to be relevant for those data directories that were generated by the wizard from a retail disc. Note the initial disc installation doesn't need to be registered as an installation because of the special case when the settings importer is run.
372 lines
12 KiB
C++
372 lines
12 KiB
C++
#include "mainwizard.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <QDateTime>
|
|
#include <QDebug>
|
|
#include <QDir>
|
|
#include <QMessageBox>
|
|
#include <QProcess>
|
|
|
|
#include <components/debug/debugging.hpp>
|
|
#include <components/files/qtconfigpath.hpp>
|
|
#include <components/files/qtconversion.hpp>
|
|
#include <components/misc/utf8qtextstream.hpp>
|
|
#include <components/process/processinvoker.hpp>
|
|
|
|
#include "componentselectionpage.hpp"
|
|
#include "conclusionpage.hpp"
|
|
#include "existinginstallationpage.hpp"
|
|
#include "importpage.hpp"
|
|
#include "installationtargetpage.hpp"
|
|
#include "intropage.hpp"
|
|
#include "languageselectionpage.hpp"
|
|
#include "methodselectionpage.hpp"
|
|
|
|
#ifdef OPENMW_USE_UNSHIELD
|
|
#include "installationpage.hpp"
|
|
#endif
|
|
|
|
Wizard::MainWizard::MainWizard(Files::ConfigurationManager&& cfgMgr, QWidget* parent)
|
|
: QWizard(parent)
|
|
, mCfgMgr(cfgMgr)
|
|
, mImporterInvoker(new Process::ProcessInvoker())
|
|
, mGameSettings(mCfgMgr)
|
|
{
|
|
#ifndef Q_OS_MAC
|
|
setWizardStyle(QWizard::ModernStyle);
|
|
#else
|
|
setWizardStyle(QWizard::ClassicStyle);
|
|
#endif
|
|
|
|
setWindowTitle(tr("OpenMW Wizard"));
|
|
setWindowIcon(QIcon(QStringLiteral(":/images/openmw-wizard.png")));
|
|
setMinimumWidth(550);
|
|
|
|
// Set the property for comboboxes to the text instead of index
|
|
setDefaultProperty("QComboBox", "currentText", "currentIndexChanged");
|
|
|
|
connect(mImporterInvoker->getProcess(), qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
|
&MainWizard::importerFinished);
|
|
|
|
Log(Debug::Info) << "Started OpenMW Wizard on " << QDateTime::currentDateTime().toString().toUtf8().constData();
|
|
|
|
std::filesystem::create_directories(mCfgMgr.getUserConfigPath());
|
|
|
|
const QString userPath(Files::pathToQString(mCfgMgr.getUserConfigPath()));
|
|
if (!QDir(userPath).exists())
|
|
{
|
|
const QString title = tr("Error creating OpenMW configuration directory");
|
|
const QString message = tr(
|
|
"<html><head/><body><p><b>Could not create %1</b></p>"
|
|
"<p>Please make sure you have the right permissions and try again.</p></body></html>");
|
|
QMessageBox::critical(nullptr, title, message.arg(userPath));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
|
|
std::filesystem::create_directories(mCfgMgr.getUserDataPath());
|
|
|
|
setupGameSettings();
|
|
setupLauncherSettings();
|
|
setupInstallations();
|
|
setupPages();
|
|
|
|
for (const std::filesystem::path& installationPath : mCfgMgr.getInstallPaths())
|
|
{
|
|
addInstallation(Files::pathToQString(installationPath / "Data Files"));
|
|
}
|
|
}
|
|
|
|
Wizard::MainWizard::~MainWizard() = default;
|
|
|
|
void Wizard::MainWizard::setupGameSettings()
|
|
{
|
|
const QString title = tr("Error opening OpenMW configuration file");
|
|
const QString message = tr(
|
|
"<html><head/><body><p><b>Could not open %1 for reading</b></p>"
|
|
"<p>Please make sure you have the right permissions and try again.</p></body></html>");
|
|
|
|
// Load the user config file first, separately
|
|
// So we can write it properly, uncontaminated
|
|
const QString path(Files::getUserConfigPathQString(mCfgMgr));
|
|
QFile file(path);
|
|
|
|
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
|
|
|
if (file.exists())
|
|
{
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
{
|
|
QMessageBox::critical(nullptr, title, message.arg(file.fileName()));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
QTextStream stream(&file);
|
|
Misc::ensureUtf8Encoding(stream);
|
|
|
|
mGameSettings.readUserFile(stream, QFileInfo(path).dir().path());
|
|
file.close();
|
|
}
|
|
|
|
// Now the rest
|
|
const QStringList paths = Files::getActiveConfigPathsQString(mCfgMgr);
|
|
|
|
for (const QString& path2 : paths)
|
|
{
|
|
qDebug() << "Loading config file:" << path2.toUtf8().constData();
|
|
|
|
file.setFileName(path2);
|
|
if (file.exists())
|
|
{
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
{
|
|
QMessageBox::critical(nullptr, title, message.arg(file.fileName()));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
QTextStream stream(&file);
|
|
Misc::ensureUtf8Encoding(stream);
|
|
|
|
mGameSettings.readFile(stream, QFileInfo(path2).dir().path());
|
|
file.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Wizard::MainWizard::setupLauncherSettings()
|
|
{
|
|
const std::filesystem::path configPath = mCfgMgr.getUserConfigPath();
|
|
const QString path(Files::pathToQString(configPath / Config::LauncherSettings::sLauncherConfigFileName));
|
|
|
|
QFile file(path);
|
|
|
|
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
|
|
|
if (file.exists())
|
|
{
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
{
|
|
const QString title = tr("Error opening OpenMW configuration file");
|
|
const QString message = tr(
|
|
"<html><head/><body><p><b>Could not open %1 for reading</b></p>"
|
|
"<p>Please make sure you have the right permissions "
|
|
"and try again.</p></body></html>");
|
|
QMessageBox::critical(nullptr, title, message.arg(file.fileName()));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
QTextStream stream(&file);
|
|
Misc::ensureUtf8Encoding(stream);
|
|
|
|
mLauncherSettings.readFile(stream);
|
|
}
|
|
}
|
|
|
|
void Wizard::MainWizard::setupInstallations()
|
|
{
|
|
// Check if the paths actually contain a Morrowind installation
|
|
for (const auto& path : mGameSettings.getDataDirs())
|
|
{
|
|
if (findFiles(QStringLiteral("Morrowind"), path.value))
|
|
addInstallation(path.value);
|
|
}
|
|
}
|
|
|
|
void Wizard::MainWizard::runSettingsImporter()
|
|
{
|
|
const QString path(field(QStringLiteral("installation.path")).toString());
|
|
const bool retailDisc(field(QStringLiteral("installation.retailDisc")).toBool());
|
|
|
|
QFile file(Files::getUserConfigPathQString(mCfgMgr));
|
|
|
|
// Construct the arguments to run the importer
|
|
QStringList arguments;
|
|
|
|
// Import plugin selection?
|
|
if (retailDisc || field(QStringLiteral("installation.import-addons")).toBool())
|
|
arguments.append(QStringLiteral("--game-files"));
|
|
|
|
arguments.append(QStringLiteral("--encoding"));
|
|
|
|
// Set encoding
|
|
const QString language(field(QStringLiteral("installation.language")).toString());
|
|
if (language == QStringLiteral("Polish"))
|
|
{
|
|
arguments.append(QStringLiteral("win1250"));
|
|
}
|
|
else if (language == QStringLiteral("Russian"))
|
|
{
|
|
arguments.append(QStringLiteral("win1251"));
|
|
}
|
|
else
|
|
{
|
|
arguments.append(QStringLiteral("win1252"));
|
|
}
|
|
|
|
// Import fonts
|
|
if (field(QStringLiteral("installation.import-fonts")).toBool())
|
|
arguments.append(QStringLiteral("--fonts"));
|
|
|
|
// Now the paths
|
|
arguments.append(QStringLiteral("--ini"));
|
|
|
|
if (retailDisc)
|
|
{
|
|
arguments.append(QDir(path).filePath(QStringLiteral("Morrowind.ini")));
|
|
}
|
|
else
|
|
{
|
|
arguments.append(mInstallations[path].iniPath);
|
|
}
|
|
|
|
arguments.append(QStringLiteral("--cfg"));
|
|
arguments.append(Files::getUserConfigPathQString(mCfgMgr));
|
|
|
|
if (!mImporterInvoker->startProcess(QStringLiteral("openmw-iniimporter"), arguments, false))
|
|
return qApp->quit();
|
|
}
|
|
|
|
void Wizard::MainWizard::addInstallation(const QString& path)
|
|
{
|
|
QDir dir(path);
|
|
if (!dir.exists())
|
|
return;
|
|
|
|
Installation install;
|
|
|
|
install.hasMorrowind = findFiles(QStringLiteral("Morrowind"), path);
|
|
install.hasTribunal = findFiles(QStringLiteral("Tribunal"), path);
|
|
install.hasBloodmoon = findFiles(QStringLiteral("Bloodmoon"), path);
|
|
|
|
QFile file(dir.filePath(QStringLiteral("Morrowind.ini")));
|
|
|
|
// Try the parent directory
|
|
// In normal Morrowind installations that's where Morrowind.ini is
|
|
if (!file.exists() && dir.cdUp())
|
|
file.setFileName(dir.filePath(QStringLiteral("Morrowind.ini")));
|
|
|
|
if (file.exists())
|
|
install.iniPath = file.fileName();
|
|
|
|
mInstallations.insert(QDir::toNativeSeparators(path), install);
|
|
}
|
|
|
|
void Wizard::MainWizard::setupPages()
|
|
{
|
|
setPage(Page_Intro, new IntroPage(this));
|
|
setPage(Page_MethodSelection, new MethodSelectionPage(this));
|
|
setPage(Page_LanguageSelection, new LanguageSelectionPage(this));
|
|
setPage(Page_ExistingInstallation, new ExistingInstallationPage(this));
|
|
setPage(Page_InstallationTarget, new InstallationTargetPage(this, mCfgMgr));
|
|
setPage(Page_ComponentSelection, new ComponentSelectionPage(this));
|
|
#ifdef OPENMW_USE_UNSHIELD
|
|
setPage(Page_Installation, new InstallationPage(this, mGameSettings));
|
|
#endif
|
|
setPage(Page_Import, new ImportPage(this));
|
|
setPage(Page_Conclusion, new ConclusionPage(this));
|
|
setStartId(Page_Intro);
|
|
}
|
|
|
|
void Wizard::MainWizard::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
|
{
|
|
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
|
|
return;
|
|
|
|
// Re-read the settings
|
|
setupGameSettings();
|
|
}
|
|
|
|
void Wizard::MainWizard::accept()
|
|
{
|
|
writeSettings();
|
|
QWizard::accept();
|
|
}
|
|
|
|
void Wizard::MainWizard::reject()
|
|
{
|
|
const QString title = tr("Quit Wizard");
|
|
const QString message = tr("Are you sure you want to exit the Wizard?");
|
|
if (QMessageBox::question(this, title, message) == QMessageBox::Yes)
|
|
QWizard::reject();
|
|
}
|
|
|
|
void Wizard::MainWizard::writeSettings()
|
|
{
|
|
// Write the encoding and language settings
|
|
const QString language(field(QStringLiteral("installation.language")).toString());
|
|
mLauncherSettings.setLanguage(language);
|
|
|
|
if (language == QStringLiteral("Polish"))
|
|
{
|
|
mGameSettings.setValue(QStringLiteral("encoding"), { "win1250" });
|
|
}
|
|
else if (language == QStringLiteral("Russian"))
|
|
{
|
|
mGameSettings.setValue(QStringLiteral("encoding"), { "win1251" });
|
|
}
|
|
else
|
|
{
|
|
mGameSettings.setValue(QStringLiteral("encoding"), { "win1252" });
|
|
}
|
|
|
|
// Write the installation path so that openmw can find them
|
|
const QString path(field(QStringLiteral("installation.path")).toString());
|
|
const QList<Config::SettingValue> dirs = mGameSettings.getDataDirs();
|
|
|
|
const QString canonical = QDir(path).canonicalPath();
|
|
|
|
// Don't write the path if it was already in the file
|
|
if (std::none_of(dirs.begin(), dirs.end(), [&](const Config::SettingValue& dir) { return dir.value == canonical; }))
|
|
mGameSettings.setMultiValue(QStringLiteral("data"), { path });
|
|
|
|
// Game settings
|
|
QFile file(Files::getUserConfigPathQString(mCfgMgr));
|
|
|
|
const QString writeTitle = tr("Error writing OpenMW configuration file");
|
|
const QString writeMessage = tr(
|
|
"<html><head/><body><p><b>Could not open %1 for writing</b></p>"
|
|
"<p>Please make sure you have the right permissions "
|
|
"and try again.</p></body></html>");
|
|
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
|
|
{
|
|
QMessageBox::critical(this, writeTitle, writeMessage.arg(file.fileName()));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
|
|
mGameSettings.writeFileWithComments(file);
|
|
file.close();
|
|
|
|
// Launcher settings
|
|
file.setFileName(
|
|
Files::pathToQString(mCfgMgr.getUserConfigPath() / Config::LauncherSettings::sLauncherConfigFileName));
|
|
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))
|
|
{
|
|
QMessageBox::critical(this, writeTitle, writeMessage.arg(file.fileName()));
|
|
QApplication::quit();
|
|
return;
|
|
}
|
|
|
|
QTextStream stream(&file);
|
|
Misc::ensureUtf8Encoding(stream);
|
|
|
|
mLauncherSettings.writeFile(stream);
|
|
file.close();
|
|
}
|
|
|
|
bool Wizard::MainWizard::findFiles(const QString& name, const QString& path)
|
|
{
|
|
const QDir dir(path);
|
|
|
|
if (!dir.exists())
|
|
return false;
|
|
|
|
const QStringList entries = dir.entryList();
|
|
// TODO: add MIME handling to make sure the files are real
|
|
return entries.contains(name + QStringLiteral(".esm"), Qt::CaseInsensitive)
|
|
&& entries.contains(name + QStringLiteral(".bsa"), Qt::CaseInsensitive);
|
|
}
|