6 #include <QStringLiteral>
8 #include "ui_interpolationlogdisplay.h"
19 using namespace swift::core::context;
21 using namespace swift::gui::editors;
23 using namespace swift::misc::aviation;
24 using namespace swift::misc::geo;
25 using namespace swift::misc::network;
26 using namespace swift::misc::simulation;
27 using namespace swift::misc::physical_quantities;
31 const QStringList &CInterpolationLogDisplay::getLogCategories()
37 CInterpolationLogDisplay::CInterpolationLogDisplay(QWidget *parent)
40 Q_ASSERT_X(
sGui, Q_FUNC_INFO,
"Need sGui");
43 ui->tw_LogTabs->setCurrentIndex(TabFlow);
44 constexpr
int timeSecs = 5;
45 ui->hs_UpdateTime->setValue(timeSecs);
46 this->onSliderChanged(timeSecs);
49 ui->led_Parts->setValues(CLedWidget::Yellow, CLedWidget::Black, shape,
"Parts received",
"", 14);
50 ui->led_Situation->setValues(CLedWidget::Yellow, CLedWidget::Black, shape,
"Situation received",
"", 14);
51 ui->led_Elevation->setValues(CLedWidget::Yellow, CLedWidget::Black, shape,
"Elevation received",
"", 14);
52 ui->led_Running->setValues(CLedWidget::Yellow, CLedWidget::Black, shape,
"Running",
"Stopped", 14);
53 ui->led_Updating->setValues(CLedWidget::Yellow, CLedWidget::Black, shape,
"Just updating",
"Idle", 14);
55 m_callsign = ui->comp_CallsignCompleter->getCallsign();
56 ui->tvp_InboundAircraftSituations->setWithMenuRequestElevation(
true);
58 m_elvHistoryModel =
new QStringListModel(
this);
59 ui->lv_ElevevationHistory->setModel(m_elvHistoryModel);
60 ui->lv_ElevevationHistory->setEditTriggers(QAbstractItemView::NoEditTriggers);
62 const int elvHistoryCount = 100;
63 m_elvHistoryCount = elvHistoryCount;
64 ui->le_ElvHistoryCount->setText(QString::number(elvHistoryCount));
66 connect(&m_updateTimer, &QTimer::timeout,
this, &CInterpolationLogDisplay::updateLog);
68 &CInterpolationLogDisplay::onCallsignEntered);
69 connect(ui->hs_UpdateTime, &QSlider::valueChanged,
this, &CInterpolationLogDisplay::onSliderChanged);
70 connect(ui->pb_StartStop, &QPushButton::released,
this, &CInterpolationLogDisplay::toggleStartStop);
71 connect(ui->pb_ResetLastSent, &QPushButton::released,
this, &CInterpolationLogDisplay::resetLastSentValues);
72 connect(ui->pb_ResetStats, &QPushButton::released,
this, &CInterpolationLogDisplay::resetStatistics);
73 connect(ui->pb_ShowLogInSimulator, &QPushButton::released,
this, &CInterpolationLogDisplay::logPosCommand);
74 connect(ui->pb_FollowInSimulator, &QPushButton::released,
this, &CInterpolationLogDisplay::followInSimulator);
75 connect(ui->pb_RequestElevation1, &QPushButton::released,
this,
76 &CInterpolationLogDisplay::requestElevationClicked);
77 connect(ui->pb_RequestElevation2, &QPushButton::released,
this,
78 &CInterpolationLogDisplay::requestElevationClicked);
79 connect(ui->pb_GetLastInterpolation, &QPushButton::released,
this,
80 &CInterpolationLogDisplay::getLogAmdDisplayLastInterpolation);
81 connect(ui->pb_InjectElevation, &QPushButton::released,
this, &CInterpolationLogDisplay::onInjectElevation);
82 connect(ui->pb_ElvClear, &QPushButton::released,
this, &CInterpolationLogDisplay::clearElevationResults);
83 connect(ui->pb_RecalcAllAircraft, &QPushButton::released,
this,
84 &CInterpolationLogDisplay::requestRecalculateAll);
85 connect(ui->pb_ClearLog, &QPushButton::released,
this, &CInterpolationLogDisplay::clearLogCommand);
86 connect(ui->pb_ClearLog2, &QPushButton::released,
this, &CInterpolationLogDisplay::clearLogCommand);
87 connect(ui->pb_WriteLogToFile, &QPushButton::released,
this, &CInterpolationLogDisplay::writeLogCommand);
88 connect(ui->pb_WriteLogToFile2, &QPushButton::released,
this, &CInterpolationLogDisplay::writeLogCommand);
89 connect(ui->le_InjectElevation, &QLineEdit::returnPressed,
this, &CInterpolationLogDisplay::onInjectElevation);
90 connect(ui->le_ElvHistoryCount, &QLineEdit::editingFinished,
this,
91 &CInterpolationLogDisplay::onElevationHistoryCountFinished);
92 connect(ui->cb_ElvAllowPseudo, &QCheckBox::toggled,
this, &CInterpolationLogDisplay::onPseudoElevationToggled);
93 connect(ui->tvp_InboundAircraftSituations, &CAircraftSituationView::requestElevation,
this,
94 &CInterpolationLogDisplay::requestElevation);
95 connect(ui->editor_ElevationCoordinate, &CCoordinateForm::changedCoordinate,
this,
96 &CInterpolationLogDisplay::requestElevationAtPosition);
98 Qt::QueuedConnection);
108 if (simulator && simulator == m_simulator) {
return; }
111 this->disconnect(m_simulator);
112 m_simulator->disconnect(
this);
114 m_simulator = simulator;
115 if (!simulator) {
return; }
116 connect(m_simulator, &ISimulator::receivedRequestedElevation,
this,
117 &CInterpolationLogDisplay::onElevationReceived, Qt::QueuedConnection);
118 connect(m_simulator, &ISimulator::requestedElevation,
this, &CInterpolationLogDisplay::onElevationRequested,
119 Qt::QueuedConnection);
120 connect(m_simulator, &ISimulator::destroyed,
this, &CInterpolationLogDisplay::onSimulatorUnloaded);
121 connect(m_simulator, &ISimulator::simulatorStatusChanged,
this,
122 &CInterpolationLogDisplay::onSimulatorStatusChanged);
127 if (airspaceMonitor && airspaceMonitor == m_airspaceMonitor) {
return; }
128 if (m_airspaceMonitor)
130 this->disconnect(m_airspaceMonitor);
131 m_airspaceMonitor->disconnect(
this);
133 m_airspaceMonitor = airspaceMonitor;
135 connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftSituation,
this,
136 &CInterpolationLogDisplay::onSituationAdded, Qt::QueuedConnection);
137 connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftParts,
this, &CInterpolationLogDisplay::onPartsAdded,
138 Qt::QueuedConnection);
141 void CInterpolationLogDisplay::updateLog()
143 ui->led_Updating->blink(250);
144 if (!this->checkLogPrerequisites())
146 ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
150 const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
154 if (ui->tw_LogTabs->currentWidget() == ui->tb_TextLog)
156 const QString log = m_simulator->latestLoggedDataFormatted(m_callsign);
157 ui->te_TextLog->setText(log);
159 else if (ui->tw_LogTabs->currentWidget() == ui->tb_DataFlow && m_airspaceMonitor)
162 m_airspaceMonitor->getSimulatorCG(m_callsign).valueRoundedWithUnit(CLengthUnit::ft(), 1));
163 ui->le_CG->home(
false);
164 ui->le_Parts->setText(boolToYesNo(m_airspaceMonitor->isRemoteAircraftSupportingParts(m_callsign)));
166 static const QString msTimeStr(
"%1ms");
167 static const QString updateTimes(
"%1ms avg: %2ms max: %3ms");
168 const QString avgUpdateTimeRounded =
169 QString::number(m_simulator->getStatisticsAverageUpdateTimeMs(),
'f', 2);
171 ui->le_UpdateTimes->setText(updateTimes.arg(m_simulator->getStatisticsCurrentUpdateTimeMs())
172 .arg(avgUpdateTimeRounded)
173 .arg(m_simulator->getStatisticsMaxUpdateTimeMs()));
174 ui->le_UpdateTimes->home(
false);
175 ui->le_UpdateCount->setText(QString::number(m_simulator->getStatisticsUpdateRuns()));
176 ui->le_UpdateReqTime->setText(msTimeStr.arg(m_simulator->getStatisticsAircraftUpdatedRequestedDeltaMs()));
177 ui->le_Limited->setText(m_simulator->updateAircraftLimitationInfo());
179 ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
180 ui->le_SimulatorSpecific->home(
false);
182 const CClient client = m_airspaceMonitor->getClientOrDefaultForCallsign(m_callsign);
185 this->displayElevationRequestReceive();
186 this->displayLastInterpolation(sLog);
188 else if (ui->tw_LogTabs->currentWidget() == ui->tb_Loopback) { this->displayLoopback(); }
191 void CInterpolationLogDisplay::getLogAmdDisplayLastInterpolation()
193 if (!this->canLog()) {
return; }
194 const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
195 this->displayLastInterpolation(sLog);
198 void CInterpolationLogDisplay::displayLastInterpolation(
const SituationLog &sLog)
200 if (!this->checkLogPrerequisites()) {
return; }
205 ui->le_SceneryOffset->setText(
207 ui->le_SceneryOffsetCG->setText(
210 const PartsLog pLog = m_simulator->interpolationLogger().getLastPartsLog();
211 ui->te_LastInterpolatedParts->setText(pLog.
parts.
toQString(
true));
214 void CInterpolationLogDisplay::displayLoopback()
216 if (!m_simulator || m_callsign.
isEmpty()) {
return; }
217 ui->tvp_LoopbackAircraftSituations->updateContainerAsync(m_simulator->getLoopbackSituations(m_callsign));
218 ui->tvp_InterpolatedAircraftSituations->updateContainerAsync(m_lastInterpolations);
221 void CInterpolationLogDisplay::onSliderChanged(
int timeSecs)
223 m_updateTimer.setInterval(timeSecs * 1000);
224 ui->le_UpdateTime->setText(QStringLiteral(
"%1secs").arg(timeSecs));
227 void CInterpolationLogDisplay::onCallsignEntered()
236 const CCallsign cs = ui->comp_CallsignCompleter->getCallsign();
237 if (m_callsign == cs) {
return; }
250 m_simulator->setLogInterpolation(
false, m_callsign);
257 m_simulator->setLogInterpolation(
true, cs);
258 ui->comp_Parts->setCallsign(cs);
259 if (!this->start()) { this->initPartsView(); }
260 CLogMessage(
this).
info(u
"Starting logging (log.display) of '%1'") << m_callsign;
263 void CInterpolationLogDisplay::onPseudoElevationToggled(
bool checked)
265 if (!this->canLog()) {
return; }
266 m_simulator->setTestEnablePseudoElevation(checked);
269 if (!ui->le_ElevationTestValue->text().isEmpty())
272 const QString v = ui->le_ElevationTestValue->text();
276 m_simulator->setTestElevation(elvTest);
279 void CInterpolationLogDisplay::toggleStartStop()
281 const bool running = m_updateTimer.isActive();
283 if (running) { this->stop(); }
287 this->onCallsignEntered();
291 void CInterpolationLogDisplay::followInSimulator()
293 if (m_callsign.
isEmpty()) {
return; }
294 if (!this->canLog()) {
return; }
295 m_simulator->followAircraft(m_callsign);
298 bool CInterpolationLogDisplay::start()
300 if (m_updateTimer.isActive()) {
return false; }
302 const int interval = 1000 * ui->hs_UpdateTime->value();
303 m_updateTimer.start(interval);
304 ui->pb_StartStop->setText(stopText());
305 ui->led_Running->setOn(
true);
307 this->initPartsView();
311 void CInterpolationLogDisplay::stop()
313 m_updateTimer.stop();
314 ui->pb_StartStop->setText(startText());
315 ui->led_Running->setOn(
false);
318 bool CInterpolationLogDisplay::logCallsign(
const CCallsign &cs)
const
321 if (!m_airspaceMonitor || !m_simulator || m_callsign.
isEmpty()) {
return false; }
322 if (cs != m_callsign) {
return false; }
326 void CInterpolationLogDisplay::onAboutToShutdown()
328 m_updateTimer.stop();
329 m_simulator =
nullptr;
332 void CInterpolationLogDisplay::onSimulatorUnloaded()
334 m_updateTimer.stop();
335 m_simulator =
nullptr;
336 this->resetStatistics();
339 void CInterpolationLogDisplay::onSimulatorStatusChanged(ISimulator::SimulatorStatus status)
342 m_updateTimer.stop();
343 this->resetStatistics();
348 static const QString info(
"times: %1 offset %2");
351 if (!this->logCallsign(cs)) {
return; }
356 ui->tvp_InboundAircraftSituations->updateContainerAsync(situations);
357 ui->tvp_Changes->updateContainerMaybeAsync(changes);
358 ui->le_InboundSituationsInfo->setText(info.arg(tsDiffMsMinMaxMean.
asString(), offsetMsMinMaxMean.
asString()));
359 ui->led_Situation->blink();
364 if (!this->logCallsign(callsign)) {
return; }
366 const CAircraftPartsList partsList = m_airspaceMonitor->remoteAircraftParts(callsign);
367 ui->tvp_InboundAircraftParts->updateContainerAsync(partsList);
368 ui->led_Parts->blink();
371 void CInterpolationLogDisplay::onElevationReceived(
const CElevationPlane &elevationPlane,
const CCallsign &callsign)
374 if (m_elvHistoryCount > 0)
376 const QString history = callsign.
asString() % QStringLiteral(
": ") %
377 QTime::currentTime().toString(
"hh:mm:ss.zzz") % QStringLiteral(
" ") %
379 m_elvHistoryModel->insertRow(0);
380 const QModelIndex index = m_elvHistoryModel->index(0, 0);
381 m_elvHistoryModel->setData(index, history);
383 const int c = m_elvHistoryModel->rowCount();
384 if (m_elvHistoryCount < c) { m_elvHistoryModel->removeRows(m_elvHistoryCount, c - m_elvHistoryCount); }
388 if (callsign == CInterpolationLogDisplay::pseudoCallsignElevation())
390 this->displayArbitraryElevation(elevationPlane);
394 if (!this->logCallsign(callsign)) {
return; }
397 m_elvReceivedLoggedCs++;
398 ui->le_Elevation->setText(elevationPlane.
toQString());
399 this->displayElevationRequestReceive();
400 ui->led_Elevation->blink();
403 void CInterpolationLogDisplay::onElevationRequested(
const CCallsign &callsign)
406 if (!this->logCallsign(callsign)) {
return; }
409 m_elvRequestedLoggedCs++;
410 this->displayElevationRequestReceive();
411 ui->led_Elevation->blink();
414 void CInterpolationLogDisplay::onInjectElevation()
416 if (!this->canLog()) {
return; }
417 const QString elv = ui->le_InjectElevation->text().trimmed();
418 if (elv.isEmpty()) {
return; }
421 if (situations.
isEmpty()) {
return; }
428 m_simulator->callbackReceivedRequestedElevation(ep, m_callsign,
false);
431 void CInterpolationLogDisplay::onElevationHistoryCountFinished()
433 const QString cs = ui->le_ElvHistoryCount->text().trimmed();
438 const int cc = cs.toInt(&ok);
441 m_elvHistoryCount = c;
444 void CInterpolationLogDisplay::resetStatistics()
446 if (m_simulator) { m_simulator->resetAircraftStatistics(); }
449 void CInterpolationLogDisplay::resetLastSentValues()
451 if (m_simulator) { m_simulator->resetLastSentValues(); }
454 void CInterpolationLogDisplay::clear()
456 ui->tvp_InboundAircraftParts->clear();
457 ui->tvp_InboundAircraftSituations->clear();
458 ui->te_TextLog->clear();
460 ui->le_Elevation->clear();
461 ui->le_ElevationReqRec->clear();
462 ui->le_ElevationReqRec->setToolTip(
"elevation requested");
463 ui->le_Parts->clear();
464 ui->le_UpdateTimes->clear();
465 ui->le_UpdateTimes->clear();
466 ui->le_Limited->clear();
467 m_elvReceivedLoggedCs = m_elvRequestedLoggedCs = 0;
468 m_elvReceived = m_elvRequested = 0;
469 m_lastInterpolations.
clear();
471 this->clearElevationResults();
474 void CInterpolationLogDisplay::clearElevationResults()
476 ui->pte_ElevationAtPosition->clear();
477 if (m_elvHistoryModel) { m_elvHistoryModel->removeRows(0, m_elvHistoryModel->rowCount()); }
480 void CInterpolationLogDisplay::logPosCommand()
482 if (m_callsign.
isEmpty()) {
return; }
485 const QString cmd = QStringLiteral(
".drv logint clear") % m_callsign.
asString();
489 void CInterpolationLogDisplay::clearLogCommand()
493 const QString cmd = QStringLiteral(
".drv logint clear");
497 void CInterpolationLogDisplay::writeLogCommand()
501 const QString cmd = QStringLiteral(
".drv logint write");
505 bool CInterpolationLogDisplay::checkLogPrerequisites()
507 using namespace std::chrono_literals;
510 if (!this->isVisible()) {
return false; }
512 if (m_callsign.isEmpty())
519 const bool canUpdateLog =
520 m_airspaceMonitor && m_simulator && m_simulator->isConnected() && !m_simulator->isShuttingDown();
529 if (!m_simulator->isLogCallsign(m_callsign))
543 void CInterpolationLogDisplay::initPartsView()
546 QPointer<CInterpolationLogDisplay> myself(
this);
548 if (!myself) {
return; }
549 if (m_callsign.
isEmpty()) { return; }
554 void CInterpolationLogDisplay::displayElevationRequestReceive()
556 if (!m_airspaceMonitor) {
return; }
557 static const QString info(
"req. %1, %2/rec. %3, %4 | found/missed: '%5' | times: %6");
558 const QString foundMissed = m_airspaceMonitor->getElevationsFoundMissedInfo();
559 const QString reqTimes = m_airspaceMonitor->getElevationRequestTimesInfo();
560 const QString reqRec = info.arg(m_elvRequestedLoggedCs)
562 .arg(m_elvReceivedLoggedCs)
564 .arg(foundMissed, reqTimes);
566 ui->le_ElevationReqRec->setText(reqRec);
567 ui->le_ElevationReqRec->setToolTip(reqRec);
568 ui->le_ElevationReqRec->home(
false);
571 void CInterpolationLogDisplay::displayArbitraryElevation(
const CElevationPlane &elevation)
573 ui->pte_ElevationAtPosition->appendPlainText(elevation.
toQString());
576 void CInterpolationLogDisplay::requestElevationClicked()
578 if (m_callsign.
isEmpty()) {
return; }
580 if (situations.
isEmpty()) {
return; }
586 if (!this->canLog()) {
return; }
587 m_simulator->requestElevationBySituation(situation);
590 void CInterpolationLogDisplay::requestElevationAtPosition()
592 if (!this->canLog()) {
return; }
594 const bool ok = m_simulator->requestElevation(coordinate, CInterpolationLogDisplay::pseudoCallsignElevation());
597 static const QString info(
"Requesting elevation: %1");
598 ui->pte_ElevationAtPosition->setPlainText(info.arg(coordinate.
toQString()));
602 static const QString info(
"Cannot request elevation");
603 ui->pte_ElevationAtPosition->setPlainText(info);
607 void CInterpolationLogDisplay::requestRecalculateAll()
609 if (!this->canLog()) {
return; }
613 bool CInterpolationLogDisplay::canLog()
const
618 const CCallsign &CInterpolationLogDisplay::pseudoCallsignElevation()
632 const QString &CInterpolationLogDisplay::startText()
634 static const QString start(
"start");
638 const QString &CInterpolationLogDisplay::stopText()
640 static const QString stop(
"stop");
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Keeps track of other entities in the airspace: aircraft, ATC stations, etc. Central instance of data ...
void aboutToShutdown()
About to shutdown.
CCoreFacade * getCoreFacade()
Get the facade.
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
bool supportsContexts(bool ignoreShutdownTest=false) const
Supports contexts.
context::CContextNetwork * getCContextNetwork()
Context for network.
Interface to a simulator.
Network context implementation.
CAirspaceMonitor * airspace() const
Airspace.
virtual bool parseCommandLine(const QString &commandLine, const swift::misc::CIdentifier &originator)=0
Parse a given command line.
virtual void recalculateAllAircraft()=0
Recalculate all aircraft.
bool showOverlayMessage(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Show single message.
Using this class provides a QFrame with the overlay functionality already integrated.
void editingFinishedDigest()
Editing finished.
Display live data of interpolation.
void setSimulator(swift::core::ISimulator *simulator)
Set simulator.
void setAirspaceMonitor(swift::core::CAirspaceMonitor *airspaceMonitor)
Set corresponding airspace monitor.
virtual ~CInterpolationLogDisplay()
Destructor.
void linkWithAirspaceMonitor()
If possible link with airspace monitor.
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
const CIdentifier & identifier() const
Get identifier.
static const QString & interpolator()
Interpolator.
static const QString & driver()
Driver.
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
bool isEmpty() const
Message empty.
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
void clear()
Removes all elements in the sequence.
bool isEmpty() const
Synonym for empty.
Streamable status message, e.g.
MillisecondsMinMaxMean getTimestampDifferenceMinMaxMean() const
Difference of timestamp values.
OBJ latestAdjustedObject() const
Latest adjusted object.
MillisecondsMinMaxMean getOffsetMinMaxMean() const
Difference of timestamp values.
void push_frontKeepLatestAdjustedFirst(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
Value object encapsulating information of aircraft's parts.
Value object encapsulating a list of aircraft parts.
const physical_quantities::CLength & getGuessedSceneryDeviation() const
Scnenery deviation (if it can be calculated, otherwise physical_quantities::CLength::null)
physical_quantities::CLength getGuessedSceneryDeviationCG() const
Get scenery deviation under consideration of CG.
Value object encapsulating a list of aircraft parts.
Value object encapsulating information of an aircraft's situation.
const CCallsign & getCallsign() const
Corresponding callsign.
List of aircraft situations.
Altitude as used in aviation, can be AGL or MSL altitude.
void parseFromString(const QString &value)
Parse value from string.
Value object encapsulating information of a callsign.
void clear()
Clear this callsign.
const QString & asString() const
Get callsign (normalized)
bool isEmpty() const
Is empty?
Plane of same elevation, can be a single point or larger area (e.g. airport)
QString toQString(bool i18n=false) const
Cast as QString.
bool hasGndFlagCapability() const
Supports gnd.flag?
Physical unit length (length)
void parseFromString(const QString &value)
Parse value from string.
bool isNull() const
Is quantity null?
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Backend services of the swift project, like dealing with the network or the simulators.
High level reusable GUI components.
Views, mainly QTableView.
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Milliseconds minimum/maximum/mean.
QString asString() const
As string.
Log entry for parts interpolation.
aviation::CAircraftParts parts
parts to be logged
Log entry for situation interpolation.
aviation::CAircraftSituation situationCurrent
interpolated situation
aviation::CAircraftSituationChange change
change