#include "installationpage.hpp" #include #include #include #include #include #include "mainwizard.hpp" Wizard::InstallationPage::InstallationPage(QWidget* parent, Config::GameSettings& gameSettings) : QWizardPage(parent) , mGameSettings(gameSettings) { mWizard = qobject_cast(parent); setupUi(this); mFinished = false; mThread = std::make_unique(); mUnshield = std::make_unique(mGameSettings.value("morrowind-bsa-filesize").value.toLongLong()); mUnshield->moveToThread(mThread.get()); connect(mThread.get(), &QThread::started, mUnshield.get(), &UnshieldWorker::extract); connect(mUnshield.get(), &UnshieldWorker::finished, mThread.get(), &QThread::quit); connect(mUnshield.get(), &UnshieldWorker::finished, this, &InstallationPage::installationFinished, Qt::QueuedConnection); connect(mUnshield.get(), &UnshieldWorker::error, this, &InstallationPage::installationError, Qt::QueuedConnection); connect( mUnshield.get(), &UnshieldWorker::textChanged, installProgressLabel, &QLabel::setText, Qt::QueuedConnection); connect(mUnshield.get(), &UnshieldWorker::textChanged, logTextEdit, &QPlainTextEdit::appendPlainText, Qt::QueuedConnection); connect( mUnshield.get(), &UnshieldWorker::textChanged, this, [](const QString& text) { Log(Debug::Info) << qUtf8Printable(text); }, Qt::QueuedConnection); connect(mUnshield.get(), &UnshieldWorker::progressChanged, installProgressBar, &QProgressBar::setValue, Qt::QueuedConnection); connect(mUnshield.get(), &UnshieldWorker::requestFileDialog, this, &InstallationPage::showFileDialog, Qt::QueuedConnection); connect(mUnshield.get(), &UnshieldWorker::requestOldVersionDialog, this, &InstallationPage::showOldVersionDialog, Qt::QueuedConnection); } Wizard::InstallationPage::~InstallationPage() { if (mThread->isRunning()) { mUnshield->stopWorker(); mThread->quit(); mThread->wait(); } } void Wizard::InstallationPage::initializePage() { const bool morrowind = field(QStringLiteral("installation.installMorrowind")).toBool(); const bool tribunal = field(QStringLiteral("installation.installTribunal")).toBool(); const bool bloodmoon = field(QStringLiteral("installation.installBloodmoon")).toBool(); const QString path = field(QStringLiteral("installation.path")).toString(); const MainWizard::Installation& installation = mWizard->mInstallations[path]; QStringList installing; if (morrowind) installing << QStringLiteral("Morrowind"); if (tribunal) installing << QStringLiteral("Tribunal"); if (bloodmoon) installing << QStringLiteral("Bloodmoon"); logTextEdit->appendPlainText(QString("Installing to %1").arg(path)); logTextEdit->appendPlainText(QString("Installing %1.").arg(installing.join(", "))); // Set the progressbar maximum to a multiple of 100 // That way installing all three components would yield 300% // When one component is done the bar will be filled by 33% int steps = 0; if (!field(QStringLiteral("installation.retailDisc")).toBool()) { steps += tribunal && !installation.hasTribunal; steps += bloodmoon && !installation.hasBloodmoon; } else { steps = installing.count(); } installProgressBar->setMinimum(0); installProgressBar->setMaximum(steps * 100); startInstallation(); } void Wizard::InstallationPage::startInstallation() { const QString path = field(QStringLiteral("installation.path")).toString(); bool hasMorrowind = false; bool hasTribunal = false; bool hasBloodmoon = false; if (!field(QStringLiteral("installation.retailDisc")).toBool()) { const MainWizard::Installation& installation = mWizard->mInstallations[path]; // Morrowind should already be installed hasMorrowind = true; hasTribunal = installation.hasTribunal; hasBloodmoon = installation.hasBloodmoon; // Set the location of the Morrowind.ini to update mUnshield->setIniPath(installation.iniPath); mUnshield->setupSettings(); } if (!hasMorrowind) mUnshield->setInstallComponent(Wizard::Component_Morrowind, true); if (!hasTribunal && field(QStringLiteral("installation.installTribunal")).toBool()) mUnshield->setInstallComponent(Wizard::Component_Tribunal, true); if (!hasBloodmoon && field(QStringLiteral("installation.installBloodmoon")).toBool()) mUnshield->setInstallComponent(Wizard::Component_Bloodmoon, true); // Set the installation target path mUnshield->setPath(path); // Set the right codec to use for Morrowind.ini const QString language(field(QStringLiteral("installation.language")).toString()); if (language == QStringLiteral("Polish")) { mUnshield->setIniEncoding(ToUTF8::FromType::WINDOWS_1250); } else if (language == QStringLiteral("Russian")) { mUnshield->setIniEncoding(ToUTF8::FromType::WINDOWS_1251); } else { mUnshield->setIniEncoding(ToUTF8::FromType::WINDOWS_1252); } mThread->start(); } void Wizard::InstallationPage::showFileDialog(Wizard::Component component) { QString name; switch (component) { case Wizard::Component_Morrowind: name = QStringLiteral("Morrowind"); break; case Wizard::Component_Tribunal: name = QStringLiteral("Tribunal"); break; case Wizard::Component_Bloodmoon: name = QStringLiteral("Bloodmoon"); break; } logTextEdit->appendHtml(tr("

Attempting to install component %1.

").arg(name)); Log(Debug::Info) << "Attempting to install component " << qUtf8Printable(name) << "."; QMessageBox msgBox(this); msgBox.setWindowTitle(tr("%1 Installation").arg(name)); msgBox.setIcon(QMessageBox::Information); msgBox.setText( QObject::tr("Select a valid %1 installation media.
Hint: make sure that it contains at least one " ".cab file.") .arg(name)); msgBox.exec(); const QString path = QFileDialog::getExistingDirectory(this, tr("Select %1 installation media").arg(name), QDir::rootPath()); if (path.isEmpty()) { logTextEdit->appendHtml( tr("


" "Error: The installation was aborted by the user

")); Log(Debug::Error) << "Error: The installation was aborted by the user"; mWizard->mError = true; emit completeChanged(); return; } mUnshield->setDiskPath(path); } void Wizard::InstallationPage::showOldVersionDialog() { logTextEdit->appendHtml(tr("

Detected old version of component Morrowind.

")); Log(Debug::Info) << "Detected old version of component Morrowind."; QMessageBox msgBox(this); msgBox.setWindowTitle(tr("Morrowind Installation")); msgBox.setIcon(QMessageBox::Information); msgBox.setText( QObject::tr("
There may be a more recent version of Morrowind available.

" "Do you wish to continue anyway?
")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); if (msgBox.exec() == QMessageBox::No) { logTextEdit->appendHtml( tr("


" "Error: The installation was aborted by the user

")); Log(Debug::Error) << "Error: The installation was aborted by the user"; mWizard->mError = true; emit completeChanged(); return; } mUnshield->wakeAll(); } void Wizard::InstallationPage::installationFinished() { QMessageBox msgBox(this); msgBox.setWindowTitle(tr("Installation finished")); msgBox.setIcon(QMessageBox::Information); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("Installation completed successfully!")); msgBox.exec(); mFinished = true; emit completeChanged(); } void Wizard::InstallationPage::installationError(const QString& text, const QString& details) { installProgressLabel->setText(tr("Installation failed!")); logTextEdit->appendHtml(tr("


Error: %1

").arg(text)); logTextEdit->appendHtml(tr("

%1

").arg(details)); Log(Debug::Error) << "Error: " << qUtf8Printable(text); Log(Debug::Error) << qUtf8Printable(details); mWizard->mError = true; QMessageBox msgBox(this); msgBox.setWindowTitle(tr("An error occurred")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText( tr("

The Wizard has encountered an error

" "

The error reported was:

%1

" "

Press "Show Details..." for more information.

") .arg(text)); msgBox.setDetailedText(details); msgBox.exec(); emit completeChanged(); } bool Wizard::InstallationPage::isComplete() const { return mWizard->mError || mFinished; } int Wizard::InstallationPage::nextId() const { if (!field(QStringLiteral("installation.retailDisc")).toBool() && !mWizard->mError) return MainWizard::Page_Import; return MainWizard::Page_Conclusion; }