/* Copyright (C) 2019 * swift project Community / Contributors * * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ #include "ui_loginadvcomponent.h" #include "loginadvcomponent.h" #include "serverlistselector.h" #include "dbquickmappingwizard.h" #include "blackgui/editors/serverform.h" #include "blackgui/editors/pilotform.h" #include "blackgui/guiapplication.h" #include "blackgui/loginmodebuttons.h" #include "blackgui/ticklabel.h" #include "blackgui/uppercasevalidator.h" #include "blackcore/context/contextaudio.h" #include "blackcore/context/contextownaircraft.h" #include "blackcore/context/contextsimulator.h" #include "blackcore/context/contextnetwork.h" #include "blackcore/data/globalsetup.h" #include "blackcore/webdataservices.h" #include "blackcore/network.h" #include "blackcore/simulator.h" #include "blackmisc/simulation/simulatorinternals.h" #include "blackmisc/simulation/aircraftmodel.h" #include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/aviation/aircrafticaocode.h" #include "blackmisc/aviation/airlineicaocode.h" #include "blackmisc/aviation/airporticaocode.h" #include "blackmisc/network/entityflags.h" #include "blackmisc/network/serverlist.h" #include "blackmisc/icons.h" #include "blackmisc/logmessage.h" #include "blackmisc/statusmessage.h" #include "blackmisc/crashhandler.h" #include "blackconfig/buildconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace BlackConfig; using namespace BlackMisc; using namespace BlackMisc::Aviation; using namespace BlackMisc::Audio; using namespace BlackMisc::Network; using namespace BlackMisc::Simulation; using namespace BlackCore; using namespace BlackCore::Data; using namespace BlackCore::Context; using namespace BlackGui; namespace BlackGui { namespace Components { const CLogCategoryList &CLoginAdvComponent::getLogCategories() { static const BlackMisc::CLogCategoryList cats { CLogCategory::guiComponent() }; return cats; } CLoginAdvComponent::CLoginAdvComponent(QWidget *parent) : COverlayMessagesFrame(parent), ui(new Ui::CLoginAdvComponent) { ui->setupUi(this); connect(ui->pb_Cancel, &QPushButton::clicked, this, &CLoginAdvComponent::loginCancelled, Qt::QueuedConnection); connect(ui->pb_Ok, &QPushButton::clicked, this, &CLoginAdvComponent::toggleNetworkConnection, Qt::QueuedConnection); connect(ui->comp_NetworkDetails, &CNetworkDetailsComponent::overridePilot, this, &CLoginAdvComponent::overrideCredentialsToPilot, Qt::QueuedConnection); connect(ui->comp_NetworkDetails, &CNetworkDetailsComponent::requestNetworkSettings, this, &CLoginAdvComponent::requestNetworkSettings, Qt::QueuedConnection); // overlay this->setOverlaySizeFactors(0.8, 0.5); this->setReducedInfo(true); this->setForceSmall(true); this->showKillButton(false); // auto logoff // we decided to make it difficult for users to disable it if (!CBuildConfig::isLocalDeveloperDebugBuild()) { ui->cb_AutoLogoff->setChecked(true); } // Stored data this->loadRememberedUserData(); // Remark: The validators affect the signals such as returnPressed, editingFinished // So I use no ranges in the CUpperCaseValidators, as this disables the signals for invalid values if (sGui && sGui->getIContextSimulator()) { connect(sGui->getIContextSimulator(), &IContextSimulator::vitalityLost, this, &CLoginAdvComponent::autoLogoffDetection, Qt::QueuedConnection); connect(sGui->getIContextSimulator(), &IContextSimulator::simulatorStatusChanged, this, &CLoginAdvComponent::onSimulatorStatusChanged, Qt::QueuedConnection); } // inital setup, if data already available ui->form_Pilot->validate(); ui->cb_AutoLogoff->setChecked(m_networkSetup.useAutoLogoff()); } CLoginAdvComponent::~CLoginAdvComponent() { } void CLoginAdvComponent::setAutoLogoff(bool autoLogoff) { ui->cb_AutoLogoff->setChecked(autoLogoff); } void CLoginAdvComponent::loginCancelled() { this->closeOverlay(); emit this->loginOrLogoffCancelled(); } void CLoginAdvComponent::toggleNetworkConnection() { if (!sGui || sGui->isShuttingDown()) { return; } if (!sGui->getIContextNetwork() || !sGui->getIContextAudio()) { return; } const bool isConnected = sGui && sGui->getIContextNetwork()->isConnected(); const bool vatsimLogin = ui->comp_NetworkDetails->isVatsimServerSelected(); m_networkSetup.setAutoLogoff(ui->cb_AutoLogoff->isChecked()); ui->form_Pilot->setVatsimValidation(vatsimLogin); CServer currentServer; // used for login CSimulatedAircraft ownAircraft; // used own aircraft CStatusMessage msg; if (!isConnected) { const CStatusMessageList aircraftMsgs = ui->comp_OwnAircraft->validate(); if (aircraftMsgs.isFailure()) { this->showOverlayHTMLMessage(CStatusMessage(this).validationWarning(u"Invalid aircraft data, login not possible"), OverlayMessageMs); return; } const CStatusMessageList pilotMsgs = ui->form_Pilot->validate(); if (pilotMsgs.isFailure()) { this->showOverlayHTMLMessage(CStatusMessage(this).validationWarning(u"Invalid pilot data, login not possible"), OverlayMessageMs); return; } // sync values with GUI values const COwnAircraftComponent::CGuiAircraftValues values = ui->comp_OwnAircraft->getAircraftValuesFromGui(); this->updateOwnAircraftCallsignAndPilotFromGuiValues(); ui->comp_OwnAircraft->updateOwnAircaftIcaoValuesFromGuiValues(); // Login mode const INetwork::LoginMode mode = ui->comp_NetworkDetails->getLoginMode(); switch (mode) { case INetwork::LoginStealth: CLogMessage(this).info(u"login in stealth mode"); break; case INetwork::LoginAsObserver: CLogMessage(this).info(u"login in observer mode"); break; default: break; // INetwork::LoginNormal } // Server currentServer = this->getCurrentServer(); const CUser user = this->getUserFromPilotGuiValues(); currentServer.setUser(user); // FSD setup, then override if (ui->comp_NetworkDetails->isFsdSetupOverrideEnabled()) { const CFsdSetup fsd = ui->comp_NetworkDetails->getFsdSetup(); currentServer.setFsdSetup(fsd); } if (ui->comp_NetworkDetails->isVoiceSetupOverrideEnabled()) { const CVoiceSetup voice = ui->comp_NetworkDetails->getVoiceSetup(); currentServer.setVoiceSetup(voice); } sGui->getIContextOwnAircraft()->updateOwnAircraftPilot(currentServer.getUser()); // set own aircraft from all values ownAircraft = sGui->getIContextOwnAircraft()->getOwnAircraft(); // Login if (sGui->getIContextAudio()) { sGui->getIContextAudio()->setVoiceSetup(currentServer.getVoiceSetup()); } msg = sGui->getIContextNetwork()->connectToNetwork(currentServer, values.ownLiverySend, values.useLivery, values.ownAircraftModelStringSend, values.useModelString, mode); if (msg.isSuccess()) { Q_ASSERT_X(currentServer.isValidForLogin(), Q_FUNC_INFO, "invalid server"); sGui->setExtraWindowTitle(QStringLiteral("[%1]").arg(ownAircraft.getCallsignAsString())); CCrashHandler::instance()->crashAndLogInfoUserName(currentServer.getUser().getRealNameAndId()); CCrashHandler::instance()->crashAndLogInfoFlightNetwork(currentServer.getEcosystem().toQString(true)); CCrashHandler::instance()->crashAndLogAppendInfo(currentServer.getServerSessionId(false)); m_networkSetup.setLastServer(currentServer); if (vatsimLogin) { m_networkSetup.setLastVatsimServer(currentServer); } } else { sGui->setExtraWindowTitle(""); } } else { // disconnect from network sGui->getIContextAudio()->leaveAllVoiceRooms(); sGui->setExtraWindowTitle(""); msg = sGui->getIContextNetwork()->disconnectFromNetwork(); } // log message and trigger events msg.addCategories(this); CLogMessage::preformatted(msg); if (msg.isSuccess()) { this->setGuiLoginAsValues(ownAircraft); emit this->loginOrLogoffSuccessful(); } else { emit this->loginOrLogoffCancelled(); } } void CLoginAdvComponent::loadRememberedUserData() { const CServer lastServer = m_networkSetup.getLastServer(); const CUser lastUser = lastServer.getUser(); ui->form_Pilot->setUser(lastUser); ui->comp_OwnAircraft->setUser(lastUser); } void CLoginAdvComponent::overrideCredentialsToPilot(const CUser &user) { ui->form_Pilot->setUser(user, true); } void CLoginAdvComponent::onSimulatorStatusChanged(int status) { ISimulator::SimulatorStatus s = static_cast(status); if (!this->hasValidContexts()) { return; } if (sGui->getIContextNetwork()->isConnected()) { if (!s.testFlag(ISimulator::Connected)) { // sim NOT connected but network connected this->autoLogoffDetection(); } } } bool CLoginAdvComponent::hasValidContexts() const { if (!sGui || !sGui->supportsContexts()) { return false; } if (sGui->isShuttingDown()) { return false; } if (!sGui->getIContextSimulator()) { return false; } if (!sGui->getIContextNetwork()) { return false; } if (!sGui->getIContextOwnAircraft()) { return false; } return true; } CUser CLoginAdvComponent::getUserFromPilotGuiValues() const { CUser user = ui->form_Pilot->getUser(); user.setCallsign(ui->comp_OwnAircraft->getCallsignFromGui()); return user; } // const bool changedOwnAircraftCallsignPilot = this->updateOwnAircraftCallsignAndPilotFromGuiValues(); // const bool changedOwnAircraftIcaoValues = this->updateOwnAircaftIcaoValuesFromGuiValues(); // if (changedOwnAircraftIcaoValues || changedOwnAircraftCallsignPilot) // { // m_changedLoginDataDigestSignal.inputSignal(); // } void CLoginAdvComponent::setGuiLoginAsValues(const CSimulatedAircraft &ownAircraft) { const QString ac( ownAircraft.getAircraftIcaoCodeDesignator() % (ownAircraft.hasAirlineDesignator() ? (u' ' % ownAircraft.getAirlineIcaoCodeDesignator()) : QString()) % (ownAircraft.hasModelString() ? (u' ' % ownAircraft.getModelString()) : QString()) ); } CServer CLoginAdvComponent::getCurrentVatsimServer() const { return ui->comp_NetworkDetails->getCurrentVatsimServer(); } CServer CLoginAdvComponent::getCurrentOtherServer() const { return ui->comp_NetworkDetails->getCurrentOtherServer(); } CServer CLoginAdvComponent::getCurrentServer() const { return ui->comp_NetworkDetails->getCurrentServer(); } void CLoginAdvComponent::autoLogoffDetection() { if (!ui->cb_AutoLogoff->isChecked()) { return; } if (!this->hasValidContexts()) { return; } if (!sGui->getIContextNetwork()->isConnected()) { return; } // nothing to logoff const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, u"Auto logoff in progress (could be simulator shutdown, crash, closing simulator)"); const int delaySecs = 30; this->showOverlayHTMLMessage(m, qRound(1000 * delaySecs * 0.8)); emit this->requestLoginPage(); } bool CLoginAdvComponent::updateOwnAircraftCallsignAndPilotFromGuiValues() { if (!this->hasValidContexts()) { return false; } CSimulatedAircraft ownAircraft(sGui->getIContextOwnAircraft()->getOwnAircraft()); const CCallsign cs = ui->comp_OwnAircraft->getCallsignFromGui(); bool changedCallsign = false; if (!cs.isEmpty() && ownAircraft.getCallsign() != cs) { sGui->getIContextOwnAircraft()->updateOwnCallsign(cs); ownAircraft.setCallsign(cs); // also update changedCallsign = true; } CUser pilot = ownAircraft.getPilot(); const CUser uiUser = ui->form_Pilot->getUser(); pilot.setRealName(uiUser.getRealName()); pilot.setHomeBase(uiUser.getHomeBase()); pilot.setId(uiUser.getId()); pilot.setCallsign(cs); bool changedPilot = false; if (ownAircraft.getPilot() != pilot) { // it can be that the callsign was changed and this results in unchanged here changedPilot = sGui->getIContextOwnAircraft()->updateOwnAircraftPilot(pilot); } return changedCallsign || changedPilot; } void CLoginAdvComponent::updateGui() { if (!this->hasValidContexts()) { return; } if (!sGui->getIContextNetwork()) { return; } const IContextNetwork *nwc = sGui->getIContextNetwork(); const bool connected = nwc->isConnected(); if (!connected) { return; } // in any case override if connected ui->comp_OwnAircraft->setOwnModelAndIcaoValues(); const CServer server = nwc->getConnectedServer(); ui->comp_NetworkDetails->setLoginMode(nwc->getLoginMode()); const CSimulatedAircraft ownAircraft = sGui->getIContextOwnAircraft()->getOwnAircraft(); this->setGuiLoginAsValues(ownAircraft); } } // namespace } // namespace