#include "oraclewizard.h" #include "client/settings/cache_settings.h" #include "main.h" #include "oracleimporter.h" #include "pages.h" #include "pagetemplates.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class QWidget; OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent) { #ifdef Q_OS_WIN setWizardStyle(QWizard::ModernStyle); #endif QString oracleSettingsFile = SettingsCache::instance().getSettingsPath() + "oracle.ini"; settings = new QSettings(oracleSettingsFile, QSettings::IniFormat, this); // We moved the oracle-specific settings from global.ini to a separate oracle.ini after 2.10 if (!QFile::exists(oracleSettingsFile)) { migrateOracleSettings(); } connect(&SettingsCache::instance().personal(), &PersonalSettings::langChanged, this, &OracleWizard::updateLanguage); importer = new OracleImporter(this); // Import card text in the language the client displays, if supported: // foreignData for any other language is never imported. importer->setCardLang(SettingsCache::instance().cardsDisplay().getCardLang()); nam = NetworkManagerFactory::create(this); QList pages; if (!isSpoilersOnly) { pages << new IntroPage << new LoadSetsPage << new SaveSetsPage << new LoadTokensPage << new OutroPage; } else { pages << new LoadSpoilersPage << new OutroPage; } for (OracleWizardPage *page : pages) { addPage(page); // Connect background auto-advance connect(page, &OracleWizardPage::readyToContinue, this, [this]() { if (backgroundMode) { next(); } }); } retranslateUi(); startRaiseServer(); } /** * Migrates the oracle-specific settings from global.ini to oracle.ini */ void OracleWizard::migrateOracleSettings() { QString filePath = SettingsCache::instance().getSettingsPath() + "global.ini"; auto globalSettings = QSettings(filePath, QSettings::IniFormat, this); auto tryMigrateValue = [this, &globalSettings](const QString &name) { QVariant variant = globalSettings.value(name); if (variant.isValid()) { settings->setValue(name, variant.toString()); } }; tryMigrateValue("allsetsurl"); tryMigrateValue("tokensurl"); tryMigrateValue("spoilersurl"); } void OracleWizard::updateLanguage() { qApp->removeTranslator(translator); installNewTranslator(); } void OracleWizard::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { retranslateUi(); } QDialog::changeEvent(event); } void OracleWizard::retranslateUi() { setWindowTitle(tr("Oracle Importer")); for (int i = 0; i < pageIds().count(); i++) { dynamic_cast(page(i))->retranslateUi(); } } void OracleWizard::accept() { QDialog::accept(); } void OracleWizard::reject() { cancelled = true; // The wizard is being closed while a page may still run a worker on the // importer. Ask it to stop before the wizard (and the importer child) is // destroyed, so the worker thread never touches freed memory. if (auto *active = dynamic_cast(currentPage())) { active->cancelWork(); } const auto replies = nam->findChildren(); for (QNetworkReply *reply : replies) { reply->abort(); } QWizard::reject(); } void OracleWizard::runInBackground() { backgroundMode = true; hide(); currentPage()->initializePage(); } void OracleWizard::startRaiseServer() { // Scope the socket name to the current user, mirroring the hosting client. raiseServer = new QLocalServer(this); connect(raiseServer, &QLocalServer::newConnection, this, &OracleWizard::handleRaiseRequest); const QString serverName = scopedLocalServerName(QStringLiteral("CockatriceOracleRaise")); if (raiseServer->listen(serverName)) { return; } // A stale socket left behind by a crashed run holds the name: take it back. QLocalServer::removeServer(serverName); if (!raiseServer->listen(serverName)) { qWarning() << "Oracle: could not listen for raise requests on" << serverName; delete raiseServer; raiseServer = nullptr; } } void OracleWizard::handleRaiseRequest() { while (raiseServer && raiseServer->hasPendingConnections()) { QLocalSocket *socket = raiseServer->nextPendingConnection(); connect(socket, &QLocalSocket::readyRead, this, [this, socket]() { socket->readAll(); socket->deleteLater(); raiseWizard(); }); connect(socket, &QLocalSocket::disconnected, socket, &QLocalSocket::deleteLater); } raiseWizard(); } void OracleWizard::raiseWizard() { // An ongoing background run is hidden; the user asked to see it, so promote it to a window. if (backgroundMode && !isVisible()) { show(); } if (isMinimized()) { showNormal(); } raise(); activateWindow(); if (windowHandle()) { windowHandle()->requestActivate(); } } void OracleWizard::enableButtons() { button(QWizard::NextButton)->setDisabled(false); button(QWizard::BackButton)->setDisabled(false); } void OracleWizard::disableButtons() { button(QWizard::NextButton)->setDisabled(true); button(QWizard::BackButton)->setDisabled(true); } bool OracleWizard::saveTokensToFile(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "File open (w) failed for" << fileName; return false; } if (file.write(tokensData) == -1) { qDebug() << "File write (w) failed for" << fileName; return false; } file.close(); return true; }