mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 04:25:35 +08:00
310 lines
14 KiB
C++
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
|