/* * mainwindow_moc.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "mainwindow_moc.h" #include "ui_mainwindow_moc.h" #include #include "../lib/CConfigHandler.h" #include "../lib/VCMIDirs.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/logging/CBasicLogConfigurator.h" #include "../lib/texts/Languages.h" #include "updatedialog_moc.h" #include "main.h" #include "helper.h" void MainWindow::load() { // Set current working dir to executable folder. // This is important on Mac for relative paths to work inside DMG. QDir::setCurrent(QApplication::applicationDirPath()); #ifndef VCMI_MOBILE console = new CConsoleHandler(); #endif CBasicLogConfigurator logConfig(VCMIDirs::get().userLogsPath() / "VCMI_Launcher_log.txt", console); logConfig.configureDefault(); CResourceHandler::initialize(); CResourceHandler::load("config/filesystem.json"); Helper::loadSettings(); } void MainWindow::computeSidePanelSizes() { QVector widgets = { ui->modslistButton, ui->settingsButton, ui->aboutButton, ui->startGameButton }; for(auto & widget : widgets) { QFontMetrics metrics(widget->font()); QSize iconSize = widget->iconSize(); // this is minimal space that is needed for our button to avoid text clipping int buttonHeight = iconSize.height() + metrics.height() + 4; widget->setMinimumHeight(buttonHeight); widget->setMaximumHeight(buttonHeight * 1.2); } } MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent), ui(new Ui::MainWindow) { load(); // load FS before UI bool setupCompleted = settings["launcher"]["setupCompleted"].Bool(); if (!setupCompleted) detectPreferredLanguage(); updateTranslation(); // load translation ui->setupUi(this); setAcceptDrops(true); setWindowIcon(QIcon{":/icons/menu-game.png"}); ui->modslistButton->setIcon(QIcon{":/icons/menu-mods.png"}); ui->settingsButton->setIcon(QIcon{":/icons/menu-settings.png"}); ui->aboutButton->setIcon(QIcon{":/icons/about-project.png"}); ui->startGameButton->setIcon(QIcon{":/icons/menu-game.png"}); #ifndef VCMI_MOBILE //load window settings QSettings s(Ui::teamName, Ui::appName); auto size = s.value("MainWindow/Size").toSize(); if(size.isValid()) { resize(size); } auto position = s.value("MainWindow/Position").toPoint(); if(!position.isNull()) { move(position); } #endif computeSidePanelSizes(); bool h3DataFound = CResourceHandler::get()->existsResource(ResourcePath("DATA/GENRLTXT.TXT")); if (h3DataFound && setupCompleted) ui->tabListWidget->setCurrentIndex(TabRows::START); else enterSetup(); ui->settingsView->setDisplayList(); if(settings["launcher"]["updateOnStartup"].Bool()) UpdateDialog::showUpdateDialog(false); } void MainWindow::detectPreferredLanguage() { auto preferredLanguages = QLocale::system().uiLanguages(); std::string selectedLanguage; for (auto const & userLang : preferredLanguages) { logGlobal->info("Preferred language: %s", userLang.toStdString()); for (auto const & vcmiLang : Languages::getLanguageList()) if (vcmiLang.tagIETF == userLang.toStdString()) selectedLanguage = vcmiLang.identifier; if (!selectedLanguage.empty()) { logGlobal->info("Selected language: %s", selectedLanguage); Settings node = settings.write["general"]["language"]; node->String() = selectedLanguage; return; } } } void MainWindow::enterSetup() { ui->startGameButton->setEnabled(false); ui->settingsButton->setEnabled(false); ui->aboutButton->setEnabled(false); ui->modslistButton->setEnabled(false); ui->tabListWidget->setCurrentIndex(TabRows::SETUP); } void MainWindow::exitSetup() { Settings writer = settings.write["launcher"]["setupCompleted"]; writer->Bool() = true; ui->startGameButton->setEnabled(true); ui->settingsButton->setEnabled(true); ui->aboutButton->setEnabled(true); ui->modslistButton->setEnabled(true); ui->tabListWidget->setCurrentIndex(TabRows::MODS); } void MainWindow::switchToStartTab() { ui->startGameButton->setEnabled(true); ui->startGameButton->setChecked(true); ui->tabListWidget->setCurrentIndex(TabRows::START); auto* startGameTabWidget = qobject_cast(ui->tabListWidget->widget(TabRows::START)); if(startGameTabWidget) startGameTabWidget->refreshState(); } void MainWindow::switchToModsTab() { ui->startGameButton->setEnabled(true); ui->modslistButton->setChecked(true); ui->tabListWidget->setCurrentIndex(TabRows::MODS); } void MainWindow::changeEvent(QEvent * event) { if(event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } QMainWindow::changeEvent(event); } MainWindow::~MainWindow() { #ifndef VCMI_MOBILE //save window settings QSettings s(Ui::teamName, Ui::appName); s.setValue("MainWindow/Size", size()); s.setValue("MainWindow/Position", pos()); #endif delete ui; } void MainWindow::on_startGameButton_clicked() { switchToStartTab(); } CModListView * MainWindow::getModView() { return ui->modlistView; } void MainWindow::on_modslistButton_clicked() { switchToModsTab(); } void MainWindow::on_settingsButton_clicked() { ui->startGameButton->setEnabled(true); ui->tabListWidget->setCurrentIndex(TabRows::SETTINGS); } void MainWindow::on_aboutButton_clicked() { ui->startGameButton->setEnabled(true); ui->tabListWidget->setCurrentIndex(TabRows::ABOUT); } void MainWindow::dragEnterEvent(QDragEnterEvent* event) { if(event->mimeData()->hasUrls()) for(const auto & url : event->mimeData()->urls()) for(const auto & ending : QStringList({".zip", ".h3m", ".h3c", ".vmap", ".vcmp", ".json", ".exe"})) if(url.fileName().endsWith(ending, Qt::CaseInsensitive)) { event->acceptProposedAction(); return; } } void MainWindow::dropEvent(QDropEvent* event) { const QMimeData* mimeData = event->mimeData(); if(mimeData->hasUrls()) { const QList urlList = mimeData->urls(); for (const auto & url : urlList) manualInstallFile(url.toLocalFile()); } } void MainWindow::manualInstallFile(QString filePath) { if(filePath.endsWith(".zip", Qt::CaseInsensitive) || filePath.endsWith(".exe", Qt::CaseInsensitive)) switchToModsTab(); QString fileName = QFileInfo{filePath}.fileName(); if(filePath.endsWith(".zip", Qt::CaseInsensitive)) getModView()->downloadFile(fileName.toLower() // mod name currently comes from zip file -> remove suffixes from github zip download .replace(QRegularExpression("-[0-9a-f]{40}"), "") .replace(QRegularExpression("-vcmi-.+\\.zip"), ".zip") .replace("-main.zip", ".zip") , QUrl::fromLocalFile(filePath), "mods"); else if(filePath.endsWith(".json", Qt::CaseInsensitive)) { QDir configDir(QString::fromStdString(VCMIDirs::get().userConfigPath().string())); QStringList configFile = configDir.entryList({fileName}, QDir::Filter::Files); // case insensitive check if(!configFile.empty()) { auto dialogResult = QMessageBox::warning(this, tr("Replace config file?"), tr("Do you want to replace %1?").arg(configFile[0]), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if(dialogResult == QMessageBox::Yes) { const auto configFilePath = configDir.filePath(configFile[0]); QFile::remove(configFilePath); QFile::copy(filePath, configFilePath); // reload settings Helper::loadSettings(); for(const auto widget : qApp->allWidgets()) if(auto settingsView = qobject_cast(widget)) settingsView->loadSettings(); getModView()->reload(); } } } else getModView()->installFiles(QStringList{filePath}); } ETranslationStatus MainWindow::getTranslationStatus() { QString preferredlanguage = QString::fromStdString(settings["general"]["language"].String()); QString installedlanguage = QString::fromStdString(settings["session"]["language"].String()); if (preferredlanguage == installedlanguage) return ETranslationStatus::ACTIVE; QString modName = getModView()->getTranslationModName(preferredlanguage); if (modName.isEmpty()) return ETranslationStatus::NOT_AVAILABLE; if (!getModView()->isModInstalled(modName)) return ETranslationStatus::NOT_INSTALLLED; if (!getModView()->isModEnabled(modName)) return ETranslationStatus::DISABLED; return ETranslationStatus::ACTIVE; } void MainWindow::updateTranslation() { #ifdef ENABLE_QT_TRANSLATIONS const std::string translationFile = settings["general"]["language"].String()+ ".qm"; QString translationFileResourcePath = QString{":/translation/%1"}.arg(translationFile.c_str()); logGlobal->info("Loading translation %s", translationFile); if(!QFile::exists(translationFileResourcePath)) { logGlobal->debug("Translation file %s does not exist", translationFileResourcePath.toStdString()); return; } if (!translator.load(translationFileResourcePath)) { logGlobal->error("Failed to load translation file %s", translationFileResourcePath.toStdString()); return; } if(translationFile == "english.qm") { // translator doesn't need to be installed for English return; } if (!qApp->installTranslator(&translator)) { logGlobal->error("Failed to install translator for translation file %s", translationFileResourcePath.toStdString()); } #endif }