/* 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 "ownaircraftcomponent.h" #include "ui_ownaircraftcomponent.h" #include "dbquickmappingwizard.h" #include "blackgui/uppercasevalidator.h" #include "blackgui/guiapplication.h" #include "blackcore/context/contextsimulator.h" #include "blackcore/context/contextownaircraft.h" #include "blackcore/context/contextnetwork.h" #include "blackcore/webdataservices.h" #include "blackcore/simulator.h" #include "blackmisc/simulation/aircraftmodel.h" #include "blackmisc/crashhandler.h" #include "blackmisc/logmessage.h" #include "blackconfig/buildconfig.h" #include using namespace BlackConfig; using namespace BlackMisc; using namespace BlackMisc::Aviation; using namespace BlackMisc::Simulation; using namespace BlackMisc::Network; using namespace BlackCore; using namespace BlackCore::Context; namespace BlackGui { namespace Components { COwnAircraftComponent::COwnAircraftComponent(QWidget *parent) : QFrame(parent), ui(new Ui::COwnAircraftComponent) { ui->setupUi(this); ui->selector_AircraftIcao->displayWithIcaoDescription(false); ui->selector_AirlineIcao->displayWithIcaoDescription(false); ui->selector_AircraftIcao->displayMode(CDbAircraftIcaoSelectorComponent::DisplayIcaoAndId); ui->selector_AirlineIcao->displayMode(CDbAirlineIcaoSelectorComponent::DisplayVDesignatorAndId); ui->cb_Model->setChecked(true); ui->cb_Livery->setChecked(true); // own aircraft ui->lblp_AircraftCombinedType->setToolTips("ok", "wrong"); ui->lblp_AirlineIcao->setToolTips("ok", "wrong"); ui->lblp_AircraftIcao->setToolTips("ok", "wrong"); ui->lblp_Callsign->setToolTips("ok", "wrong"); constexpr int MaxLength = 10; constexpr int MinLength = 0; CUpperCaseValidator *ucv = new CUpperCaseValidator(MinLength, MaxLength, ui->le_Callsign); ucv->setAllowedCharacters09AZ(); ui->le_Callsign->setMaxLength(MaxLength); ui->le_Callsign->setValidator(ucv); ui->le_AircraftCombinedType->setMaxLength(3); ui->le_AircraftCombinedType->setValidator(new CUpperCaseValidator(this)); ui->comp_ModelStringCompleter->setSourceVisible(CAircraftModelStringCompleter::OwnModels, false); ui->comp_ModelStringCompleter->selectSource(CAircraftModelStringCompleter::ModelSet); connect(ui->le_Callsign, &QLineEdit::editingFinished, this, &COwnAircraftComponent::validate); connect(ui->comp_ModelStringCompleter, &CAircraftModelStringCompleter::modelStringChanged, this, &COwnAircraftComponent::onModelStringSendChanged); connect(ui->le_AircraftCombinedType, &QLineEdit::editingFinished, this, &COwnAircraftComponent::validate); connect(ui->selector_AircraftIcao, &CDbAircraftIcaoSelectorComponent::changedAircraftIcao, this, &COwnAircraftComponent::changedAircraftIcao, Qt::QueuedConnection); connect(ui->selector_AirlineIcao, &CDbAirlineIcaoSelectorComponent::changedAirlineIcao, this, &COwnAircraftComponent::changedAirlineIcao, Qt::QueuedConnection); connect(ui->pb_SimulatorLookup, &QPushButton::clicked, this, &COwnAircraftComponent::lookupOwnAircraftModel); connect(ui->pb_MappingWizard, &QPushButton::clicked, this, &COwnAircraftComponent::mappingWizard, Qt::QueuedConnection); connect(ui->pb_Clear, &QPushButton::clicked, this, &COwnAircraftComponent::clearLivery, Qt::QueuedConnection); if (sGui && sGui->getIContextSimulator()) { connect(sGui->getIContextSimulator(), &IContextSimulator::ownAircraftModelChanged, this, &COwnAircraftComponent::onSimulatorModelChanged, Qt::QueuedConnection); connect(sGui->getIContextSimulator(), &IContextSimulator::simulatorStatusChanged, this, &COwnAircraftComponent::onSimulatorStatusChanged, Qt::QueuedConnection); } if (sGui && sGui->getIContextOwnAircraft()) { this->onSimulatorModelChanged(sGui->getIContextOwnAircraft()->getOwnAircraft().getModel()); } } COwnAircraftComponent::~COwnAircraftComponent() { } void COwnAircraftComponent::setUser(const CUser &user) { if (user.hasCallsign()) { ui->le_Callsign->setText(user.getCallsign().asString()); } else if (CBuildConfig::isLocalDeveloperDebugBuild()) { ui->le_Callsign->setText("SWIFT"); } } void COwnAircraftComponent::lookupOwnAircraftModel() { if (!this->hasValidContexts()) { return; } if (!sGui->getIContextSimulator()->isSimulatorAvailable()) { return; } const CAircraftModel model(sGui->getIContextOwnAircraft()->getOwnAircraft().getModel()); this->onSimulatorModelChanged(model); } void COwnAircraftComponent::onSimulatorModelChanged(const CAircraftModel &model) { if (!sGui || !sGui->getIContextNetwork() || sApp->isShuttingDown()) { return; } const bool isNetworkConnected = sGui && sGui->getIContextNetwork()->isConnected(); if (isNetworkConnected) { return; } // update with latest DB data CAircraftModel reverseModel(model); if (sGui->hasWebDataServices()) { reverseModel = sGui->getWebDataServices()->getModelForModelString(model.getModelString()); if (!reverseModel.isLoadedFromDb()) { reverseModel = model; } // reset if not found } const QString modelStr(reverseModel.hasModelString() ? reverseModel.getModelString() : ""); if (!reverseModel.hasModelString()) { CLogMessage(this).validationInfo(u"Invalid lookup for '%1' successful: %2") << modelStr << reverseModel.toQString(); CLogMessage(this).validationInfo(u"Hint: Are you using the emulated driver? Set a model if so!"); return; } this->setOwnModelAndIcaoValues(reverseModel); // open dialog for model mapping if (m_autoPopupWizard && !reverseModel.isLoadedFromDb()) { this->mappingWizard(); } emit this->aircraftDataChanged(); } void COwnAircraftComponent::onModelStringSendChanged() { if (!this->hasValidContexts()) { return; } if (!sGui->hasWebDataServices()) { return; } const QString modelString = ui->comp_ModelStringCompleter->getModelString(); if (modelString.isEmpty()) { return; } // keep last values const CAircraftModel model = sGui->getWebDataServices()->getModelForModelString(modelString); this->setGuiIcaoValues(model, false); } void COwnAircraftComponent::onSimulatorStatusChanged(int status) { ISimulator::SimulatorStatus s = static_cast(status); Q_UNUSED(s); if (!this->hasValidContexts()) { return; } if (sGui->getIContextNetwork()->isConnected()) { // void } } CStatusMessageList COwnAircraftComponent::validate() const { CGuiAircraftValues values = this->getAircraftValuesFromGui(); CStatusMessageList msgs; // fill in combined type if empty if (ui->le_AircraftCombinedType->text().isEmpty() && values.ownAircraftIcao.isLoadedFromDb()) { ui->le_AircraftCombinedType->setText(values.ownAircraftIcao.getCombinedType()); values.ownAircraftCombinedType = values.ownAircraftIcao.getCombinedType(); } const bool validCombinedType = CAircraftIcaoCode::isValidCombinedType(values.ownAircraftCombinedType); ui->lblp_AircraftCombinedType->setTicked(validCombinedType); if (!validCombinedType) { msgs.addValidationMessage("Invalid combined type", CStatusMessage::SeverityError); } // airline is optional, e.g. C172 has no airline const bool validAirlineDesignator = values.ownAirlineIcao.hasValidDesignator() || values.ownAirlineIcao.getDesignator().isEmpty(); ui->lblp_AirlineIcao->setTicked(validAirlineDesignator); if (!validAirlineDesignator) { msgs.addValidationMessage("Invalid airline designator", CStatusMessage::SeverityError); } const bool validAircraftDesignator = values.ownAircraftIcao.hasValidDesignator(); ui->lblp_AircraftIcao->setTicked(validAircraftDesignator); if (!validAircraftDesignator) { msgs.addValidationMessage("Invalid aircraft designator", CStatusMessage::SeverityError); } const bool validCallsign = CCallsign::isValidAircraftCallsign(values.ownCallsign); ui->lblp_Callsign->setTicked(validCallsign); if (!validCallsign) { msgs.addValidationMessage("Invalid callsign", CStatusMessage::SeverityError); } // model intentionally ignored // return validCombinedType && validAirlineDesignator && validAircraftDesignator && validCallsign; return msgs; } void COwnAircraftComponent::changedAircraftIcao(const CAircraftIcaoCode &icao) { if (icao.isLoadedFromDb()) { ui->le_AircraftCombinedType->setText(icao.getCombinedType()); } this->validate(); } COwnAircraftComponent::CGuiAircraftValues COwnAircraftComponent::getAircraftValuesFromGui() const { CGuiAircraftValues values; values.ownCallsign = CCallsign(ui->le_Callsign->text().trimmed().toUpper()); values.ownAircraftIcao = ui->selector_AircraftIcao->getAircraftIcao(); values.ownAirlineIcao = ui->selector_AirlineIcao->getAirlineIcao(); values.ownAircraftCombinedType = ui->le_AircraftCombinedType->text().trimmed().toUpper(); values.ownAircraftSimulatorModelString = ui->le_SimulatorModel->text().trimmed().toUpper(); values.ownAircraftModelStringSend = ui->comp_ModelStringCompleter->getModelString().toUpper(); values.ownLiverySend = ui->le_SendLivery->text().trimmed().toUpper(); values.useLivery = ui->cb_Livery->isChecked(); values.useModelString = ui->cb_Model->isChecked(); return values; } CCallsign COwnAircraftComponent::getCallsignFromGui() const { const CCallsign cs(ui->le_Callsign->text().trimmed().toUpper()); return cs; } void COwnAircraftComponent::changedAirlineIcao(const CAirlineIcaoCode &icao) { Q_UNUSED(icao); this->validate(); } bool COwnAircraftComponent::setGuiIcaoValues(const CAircraftModel &model, bool onlyIfEmpty) { bool changed = false; if (!onlyIfEmpty || !ui->selector_AircraftIcao->isSet()) { changed = ui->selector_AircraftIcao->setAircraftIcao(model.getAircraftIcaoCode()); } if (!onlyIfEmpty || !ui->selector_AirlineIcao->isSet()) { const bool c = ui->selector_AirlineIcao->setAirlineIcao(model.getAirlineIcaoCode()); changed |= c; } if (!onlyIfEmpty || ui->le_AircraftCombinedType->text().trimmed().isEmpty()) { const QString combined(model.getAircraftIcaoCode().getCombinedType()); if (ui->le_AircraftCombinedType->text() != combined) { ui->le_AircraftCombinedType->setText(combined); changed = true; } } if (!onlyIfEmpty || ui->le_SendLivery->text().trimmed().isEmpty()) { const QString ls(model.getSwiftLiveryString()); if (ui->le_SendLivery->text() != ls) { ui->le_SendLivery->setText(ls); changed = true; } } const bool valid = this->validate().isSuccess(); return valid ? changed : false; } void COwnAircraftComponent::highlightModelField(const CAircraftModel &model) { if (!model.hasModelString()) { ui->le_SimulatorModel->setProperty("validation", "error"); } else if (!model.isLoadedFromDb()) { ui->le_SimulatorModel->setProperty("validation", "warning"); } else { ui->le_SimulatorModel->setProperty("validation", "ok"); } ui->le_SimulatorModel->setStyleSheet(""); // force update } bool COwnAircraftComponent::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; } void COwnAircraftComponent::clearLivery() { ui->le_SendLivery->clear(); } CAircraftModel COwnAircraftComponent::getPrefillModel() const { const CAircraftModel model = m_lastAircraftModel.get(); if (model.hasAircraftDesignator()) { return model; } return IContextOwnAircraft::getDefaultOwnAircraftModel(); } void COwnAircraftComponent::setOwnModelAndIcaoValues(const CAircraftModel &ownModel) { if (!this->hasValidContexts()) { return; } CAircraftModel model = ownModel; const bool simulating = sGui->getIContextSimulator() && (sGui->getIContextSimulator()->getSimulatorStatus() & ISimulator::Simulating); if (simulating) { if (!model.hasModelString()) { model = sGui->getIContextOwnAircraft()->getOwnAircraft().getModel(); } const QString modelAndKey(model.getModelStringAndDbKey()); ui->le_SimulatorModel->setText(modelAndKey); ui->le_SimulatorModel->home(false); this->highlightModelField(model); const CSimulatorInfo sim = sGui->getIContextSimulator()->getSimulatorPluginInfo().getSimulator(); ui->comp_ModelStringCompleter->setSimulator(sim); m_lastAircraftModel.set(model); const CSimulatorInternals simulatorInternals = sGui->getIContextSimulator()->getSimulatorInternals(); const QString simStr = sim.toQString() + QStringLiteral(" ") + simulatorInternals.getSimulatorVersion(); CCrashHandler::instance()->crashAndLogInfoSimulator(simStr); } else { if (!model.hasModelString()) { model = this->getPrefillModel(); } ui->le_SimulatorModel->clear(); this->highlightModelField(); } ui->le_SimulatorModel->setToolTip(model.asHtmlSummary()); ui->comp_ModelStringCompleter->setText(model.getModelString()); ui->le_SendLivery->setText(model.getSwiftLiveryString()); // reset the model if (model.isLoadedFromDb() || (model.getAircraftIcaoCode().isLoadedFromDb() && model.getLivery().isLoadedFromDb())) { // full model from DB, take all values this->setGuiIcaoValues(model, false); } else { if (sGui->getIContextSimulator()->isSimulatorAvailable()) { // sim. attached, but no model data from DB ui->le_AircraftCombinedType->clear(); ui->selector_AircraftIcao->clear(); ui->selector_AirlineIcao->clear(); } } } void COwnAircraftComponent::mappingWizard() { if (!sGui || !sGui->getIContextOwnAircraft() || sGui->isShuttingDown()) { return; } if (!sGui->hasMinimumMappingVersion()) { return; } if (!m_mappingWizard) { m_mappingWizard.reset(new CDbQuickMappingWizard(this)); } if (sGui->getIContextSimulator()->isSimulatorAvailable()) { // preset on model const CAircraftModel model(sGui->getIContextOwnAircraft()->getOwnAircraft().getModel()); m_mappingWizard->presetModel(model); } else { // preset on GUI values only const CAircraftIcaoCode icao(ui->selector_AircraftIcao->getAircraftIcao()); m_mappingWizard->presetAircraftIcao(icao); } m_mappingWizard->show(); } bool COwnAircraftComponent::updateOwnAircaftIcaoValuesFromGuiValues() { if (!this->hasValidContexts()) { return false; } const CSimulatedAircraft ownAircraft(sGui->getIContextOwnAircraft()->getOwnAircraft()); const CGuiAircraftValues aircraftValues = this->getAircraftValuesFromGui(); CAircraftIcaoCode aircraftCode(ownAircraft.getAircraftIcaoCode()); CAirlineIcaoCode airlineCode(ownAircraft.getAirlineIcaoCode()); bool changedIcaoCodes = false; if (aircraftValues.ownAircraftIcao.hasValidDesignator() && aircraftValues.ownAircraftIcao != aircraftCode) { aircraftCode = aircraftValues.ownAircraftIcao; changedIcaoCodes = true; } if (aircraftValues.ownAirlineIcao.hasValidDesignator() && aircraftValues.ownAirlineIcao != airlineCode) { airlineCode = aircraftValues.ownAirlineIcao; changedIcaoCodes = true; } if (changedIcaoCodes) { sGui->getIContextOwnAircraft()->updateOwnIcaoCodes(aircraftCode, airlineCode); } return changedIcaoCodes; } } // ns } // ns