#include "mainwizard.hpp" #include #include #include #include #include #include #include #include #include #include #include #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(&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( "

Could not create %1

" "

Please make sure you have the right permissions and try again.

"); 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( "

Could not open %1 for reading

" "

Please make sure you have the right permissions and try again.

"); // 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( "

Could not open %1 for reading

" "

Please make sure you have the right permissions " "and try again.

"); 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 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( "

Could not open %1 for writing

" "

Please make sure you have the right permissions " "and try again.

"); 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); }