Files
pilotclient/src/blackgui/components/modelmatchercomponent.cpp

310 lines
14 KiB
C++

/* Copyright (C) 2016
* 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 "aircraftcombinedtypeselector.h"
#include "dbaircrafticaoselectorcomponent.h"
#include "dbairlineicaoselectorcomponent.h"
#include "dbliveryselectorcomponent.h"
#include "modelmatchercomponent.h"
#include "settingsmatchingdialog.h"
#include "simulatorselector.h"
#include "blackgui/models/statusmessagelistmodel.h"
#include "blackgui/views/statusmessageview.h"
#include "blackgui/views/aircraftmodelview.h"
#include "blackgui/uppercasevalidator.h"
#include "blackgui/guiapplication.h"
#include "blackgui/guiutility.h"
#include "blackcore/webdataservices.h"
#include "blackmisc/simulation/data/modelcaches.h"
#include "blackmisc/simulation/matchingutils.h"
#include "blackmisc/aviation/logutils.h"
#include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/airlineicaocode.h"
#include "blackmisc/aviation/callsign.h"
#include "blackmisc/aviation/livery.h"
#include "blackmisc/network/user.h"
#include "blackmisc/statusmessagelist.h"
#include "ui_modelmatchercomponent.h"
#include <QCheckBox>
#include <QCompleter>
#include <QLineEdit>
#include <QPushButton>
#include <QStringList>
#include <QStringBuilder>
#include <QTabWidget>
#include <QTextEdit>
#include <QtGlobal>
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::Simulation::Data;
using namespace BlackMisc::Network;
using namespace BlackGui::Models;
using namespace BlackGui::Views;
using namespace BlackCore;
namespace BlackGui
{
namespace Components
{
CModelMatcherComponent::CModelMatcherComponent(QWidget *parent) :
QFrame(parent),
ui(new Ui::CModelMatcherComponent)
{
Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
Q_ASSERT_X(sGui->getWebDataServices(), Q_FUNC_INFO, "Missing web services");
ui->setupUi(this);
ui->comp_SimulatorSelector->setMode(CSimulatorSelector::RadioButtons);
ui->comp_SimulatorSelector->setRememberSelectionAndSetToLastSelection();
ui->comp_AirlineSelector->displayWithIcaoDescription(false);
ui->comp_AircraftSelector->displayWithIcaoDescription(false);
ui->comp_LiverySelector->withLiveryDescription(false);
ui->tvp_ResultMessages->setMode(CStatusMessageListModel::Simplified);
ui->tvp_ResultMessages->menuAddItems(CViewBaseNonTemplate::MenuSave);
const CUpperCaseValidator *validator = new CUpperCaseValidator(this);
ui->le_ModelString->setValidator(validator);
ui->le_Manufacturer->setValidator(validator);
ui->le_Callsign->setValidator(validator);
connect(ui->comp_SimulatorSelector, &CSimulatorSelector::changed, this, &CModelMatcherComponent::onSimulatorChanged);
connect(sGui->getWebDataServices(), &CWebDataServices::dataRead, this, &CModelMatcherComponent::onWebDataRead, Qt::QueuedConnection);
connect(ui->pb_ModelMatching, &QPushButton::pressed, this, &CModelMatcherComponent::testModelMatching);
connect(ui->pb_ReverseLookup, &QPushButton::pressed, this, &CModelMatcherComponent::reverseLookup);
connect(ui->pb_Settings, &QPushButton::pressed, this, &CModelMatcherComponent::displaySettingsDialog);
connect(ui->cb_UseWorkbench, &QCheckBox::toggled, this, &CModelMatcherComponent::onWorkbenchToggled);
// initial settings
m_matcher.setSetup(m_matchingSettings.get());
this->redisplay();
ui->cb_UseWorkbench->setVisible(false);
}
CModelMatcherComponent::~CModelMatcherComponent()
{ }
void CModelMatcherComponent::tabIndexChanged(int index)
{
if (index < 0) { return; }
const QTabWidget *tw = CGuiUtility::parentTabWidget(this);
Q_ASSERT_X(tw, Q_FUNC_INFO, "Cannot find parent tab widget");
const QWidget *tabWidget = tw->currentWidget();
const QWidget *myselfTabWidget = this->parentWidget();
if (tabWidget != myselfTabWidget) { return; }
this->redisplay();
}
void CModelMatcherComponent::setWorkbenchView(Views::CAircraftModelView *workbenchView)
{
if (workbenchView)
{
ui->cb_UseWorkbench->setVisible(true);
m_workbenchView = workbenchView;
}
else
{
ui->cb_UseWorkbench->setVisible(false);
m_workbenchView.clear();
}
}
void CModelMatcherComponent::onSimulatorChanged(const CSimulatorInfo &simulator)
{
Q_ASSERT_X(simulator.isSingleSimulator(), Q_FUNC_INFO, "Need single simulator");
ui->tvp_ResultMessages->clear();
if (this->useWorkbench())
{
const CAircraftModelList models = m_workbenchView->container();
if (models.isEmpty())
{
CStatusMessage m(this, CStatusMessage::SeverityWarning, u"No models in workbench, disabled.");
ui->tvp_ResultMessages->insert(m);
return;
}
CSimulatorInfo simulator = models.simulatorsWithMaxEntries();
m_matcher.setModelSet(models, simulator, true);
}
else
{
const CAircraftModelList models = CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().getCachedModels(simulator);
m_matcher.setModelSet(models, simulator, true);
}
this->redisplay();
}
void CModelMatcherComponent::onWorkbenchToggled(bool checked)
{
Q_UNUSED(checked);
this->onSimulatorChanged(ui->comp_SimulatorSelector->getValue());
}
void CModelMatcherComponent::onCacheChanged(CSimulatorInfo &simulator)
{
Q_UNUSED(simulator);
this->redisplay();
}
void CModelMatcherComponent::testModelMatching()
{
ui->te_Results->clear();
this->onSimulatorChanged(ui->comp_SimulatorSelector->getValue()); // update model set to latest version
CStatusMessageList msgs;
CSimulatedAircraft remoteAircraft(this->createAircraft());
m_matcher.setDefaultModel(CModelMatcherComponent::defaultModel());
if (ui->cb_withReverseLookup->isChecked())
{
const QString liveryString(ui->comp_LiverySelector->getRawCombinedCode());
const CAircraftModelList modelSet = m_matcher.getModelSet();
const CAircraftMatcherSetup setup = m_matcher.getSetup();
const CAircraftModel reverseModel = CAircraftMatcher::reverseLookupModelMs(remoteAircraft.getModel(), liveryString, setup, modelSet, &msgs);
remoteAircraft.setModel(reverseModel); // current model
}
CStatusMessageList matchingMsgs;
const CAircraftModel matched = m_matcher.getClosestMatch(remoteAircraft, MatchingLogAll, &matchingMsgs, true); // test model matching
msgs.push_back(matchingMsgs);
ui->te_Results->setText(matched.toQString(true));
ui->tvp_ResultMessages->updateContainer(msgs);
ui->tvp_ResultMessages->fullResizeToContents();
ui->tvp_ResultMessages->resizeRowsToContents();
}
void CModelMatcherComponent::reverseLookup()
{
// CAirspaceMonitor::reverseLookupModelWithFlightplanData is the real world lookup
ui->te_Results->clear();
CStatusMessageList msgs;
m_matcher.setDefaultModel(CModelMatcherComponent::defaultModel());
const CAircraftModelList modelSet = m_matcher.getModelSet();
const CAircraftMatcherSetup setup = m_matcher.getSetup();
const CSimulatedAircraft remoteAircraft(createAircraft());
const QString livery(ui->comp_LiverySelector->getRawCombinedCode());
const CAircraftModel matched = CAircraftMatcher::reverseLookupModelMs(remoteAircraft.getModel(), livery, setup, modelSet, &msgs);
ui->te_Results->setText(matched.toQString(true));
ui->tvp_ResultMessages->updateContainer(msgs);
}
void CModelMatcherComponent::onWebDataRead(CEntityFlags::Entity entity, CEntityFlags::ReadState state, int number, const QUrl &url)
{
Q_UNUSED(url)
if (!sGui || sGui->isShuttingDown()) { return; }
if (number > 0 && entity.testFlag(CEntityFlags::ModelEntity) && CEntityFlags::isFinishedReadState(state))
{
const QStringList modelStrings(sGui->getWebDataServices()->getModelStrings(true));
ui->le_ModelString->setCompleter(new QCompleter(modelStrings, this));
}
}
void CModelMatcherComponent::displaySettingsDialog()
{
if (!m_settingsDialog) { m_settingsDialog = new CSettingsMatchingDialog(this); }
m_settingsDialog->setMatchingSetup(m_matcher.getSetup());
const QDialog::DialogCode r = static_cast<QDialog::DialogCode>(m_settingsDialog->exec());
if (r == QDialog::Accepted)
{
m_matcher.setSetup(m_settingsDialog->getMatchingSetup());
}
}
void CModelMatcherComponent::redisplay()
{
const int c = this->getMatcherModelsCount();
ui->le_ModelSetCount->setText(QString::number(c) % (this->useWorkbench() ? u" (workbench)" : u""));
}
CAircraftModelList CModelMatcherComponent::getModelSetModels() const
{
const CSimulatorInfo simulator = ui->comp_SimulatorSelector->getValue();
const CAircraftModelList models = CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().getCachedModels(simulator);
return models;
}
int CModelMatcherComponent::getMatcherModelsCount() const
{
return m_matcher.getModelSetCount();
}
bool CModelMatcherComponent::useWorkbench() const
{
return ui->cb_UseWorkbench->isChecked() && m_workbenchView;
}
CSimulatedAircraft CModelMatcherComponent::createAircraft() const
{
const QString airline(ui->comp_AirlineSelector->getRawDesignator());
const QString aircraft(ui->comp_AircraftSelector->getRawDesignator());
const QString modelString(ui->le_ModelString->text().trimmed().toUpper());
const QString combined(ui->comp_CombinedCode->getCombinedType());
const QString manufacturer(ui->le_Manufacturer->text().trimmed().toUpper());
const QString liveryCombinedCode(ui->comp_LiverySelector->getRawCombinedCode());
const CCallsign cs(ui->le_Callsign->text().isEmpty() ? "SWIFT" : ui->le_Callsign->text()); // need callsign
static const CUser pilot("123456", "swift Test", cs);
CAircraftIcaoCode icao(aircraft, combined);
icao.setManufacturer(manufacturer);
const CAirlineIcaoCode airlineIcao(airline);
const CLivery livery(liveryCombinedCode, airlineIcao, "");
CAircraftModel m(modelString, CAircraftModel::TypeFSInnData);
m.setLivery(livery);
m.setCallsign(cs);
m.setModelType(modelString.isEmpty() ? CAircraftModel::TypeQueriedFromNetwork : CAircraftModel::TypeFSInnData);
CSimulatedAircraft sa(m);
sa.setPilot(pilot);
sa.setAircraftIcaoCode(icao);
return sa;
}
CAircraftModel CModelMatcherComponent::defaultModel() const
{
// can somehow dynamilcally determine the models
const CAircraftIcaoCode icaoAircraft("B737", "L2J", "FooBar", "Dummy", "M", false, false, false, 1);
const CAirlineIcaoCode icaoAirline("Foo", "FooBar airlines", { "DE", "Germany" }, "FOO", true, true);
const CLivery livery(CLivery::getStandardCode(icaoAirline), icaoAirline, "Standard Foo airlines", "red", "blue", false);
CAircraftModel model("default model", CAircraftModel::TypeOwnSimulatorModel, "dummy model", icaoAircraft, livery);
if (model.getCallsign().isEmpty()) { model.setCallsign("SWIFT"); }
return model;
}
MatchingScriptReturnValues CModelMatcherComponent::matchingScript(const CAircraftModel &inModel, const CAircraftMatcherSetup &setup, const CAircraftModelList &modelSet, CStatusMessageList &msgs)
{
// Script
if (setup.doRunMsReverseLookupScript())
{
const MatchingScriptReturnValues rv = CAircraftMatcher::reverseLookupScript(inModel, setup, modelSet, &msgs);
if (rv.runScriptAndModified())
{
return rv;
}
else
{
CLogUtilities::addLogDetailsToList(&msgs, inModel.getCallsign(), QStringLiteral("Matching script, no modification"));
}
}
else
{
CLogUtilities::addLogDetailsToList(&msgs, inModel.getCallsign(), QStringLiteral("No reverse lookup script used"));
}
return inModel;
}
} // ns
} // ns