Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372#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);}