swift
interpolationlogdisplay.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QStringLiteral>
7 
8 #include "ui_interpolationlogdisplay.h"
9 
10 #include "core/airspacemonitor.h"
14 #include "gui/guiapplication.h"
15 #include "misc/stringutils.h"
17 
18 using namespace swift::core;
19 using namespace swift::core::context;
20 using namespace swift::gui::views;
21 using namespace swift::gui::editors;
22 using namespace swift::misc;
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;
28 
29 namespace swift::gui::components
30 {
31  const QStringList &CInterpolationLogDisplay::getLogCategories()
32  {
33  static const QStringList cats { CLogCategories::interpolator(), CLogCategories::driver() };
34  return cats;
35  }
36 
37  CInterpolationLogDisplay::CInterpolationLogDisplay(QWidget *parent)
39  {
40  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
41 
42  ui->setupUi(this);
43  ui->tw_LogTabs->setCurrentIndex(TabFlow);
44  constexpr int timeSecs = 5;
45  ui->hs_UpdateTime->setValue(timeSecs);
46  this->onSliderChanged(timeSecs);
47 
48  const CLedWidget::LedShape shape = CLedWidget::Rounded;
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);
54 
55  m_callsign = ui->comp_CallsignCompleter->getCallsign();
56  ui->tvp_InboundAircraftSituations->setWithMenuRequestElevation(true);
57 
58  m_elvHistoryModel = new QStringListModel(this);
59  ui->lv_ElevevationHistory->setModel(m_elvHistoryModel);
60  ui->lv_ElevevationHistory->setEditTriggers(QAbstractItemView::NoEditTriggers);
61 
62  const int elvHistoryCount = 100;
63  m_elvHistoryCount = elvHistoryCount;
64  ui->le_ElvHistoryCount->setText(QString::number(elvHistoryCount));
65 
66  connect(&m_updateTimer, &QTimer::timeout, this, &CInterpolationLogDisplay::updateLog);
67  connect(ui->comp_CallsignCompleter, &CCallsignCompleter::editingFinishedDigest, this,
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);
97  connect(sGui, &CGuiApplication::aboutToShutdown, this, &CInterpolationLogDisplay::onAboutToShutdown,
98  Qt::QueuedConnection);
99  }
100 
102  {
103  // void
104  }
105 
107  {
108  if (simulator && simulator == m_simulator) { return; } // same
109  if (m_simulator)
110  {
111  this->disconnect(m_simulator);
112  m_simulator->disconnect(this);
113  }
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);
123  }
124 
126  {
127  if (airspaceMonitor && airspaceMonitor == m_airspaceMonitor) { return; } // same
128  if (m_airspaceMonitor)
129  {
130  this->disconnect(m_airspaceMonitor);
131  m_airspaceMonitor->disconnect(this);
132  }
133  m_airspaceMonitor = airspaceMonitor;
134 
135  connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftSituation, this,
136  &CInterpolationLogDisplay::onSituationAdded, Qt::QueuedConnection);
137  connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftParts, this, &CInterpolationLogDisplay::onPartsAdded,
138  Qt::QueuedConnection);
139  }
140 
141  void CInterpolationLogDisplay::updateLog()
142  {
143  ui->led_Updating->blink(250);
144  if (!this->checkLogPrerequisites())
145  {
146  ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
147  return;
148  }
149 
150  const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
151  m_lastInterpolations.push_frontKeepLatestAdjustedFirst(sLog.situationCurrent, true, 10);
152 
153  // only display visible tab
154  if (ui->tw_LogTabs->currentWidget() == ui->tb_TextLog)
155  {
156  const QString log = m_simulator->latestLoggedDataFormatted(m_callsign);
157  ui->te_TextLog->setText(log);
158  }
159  else if (ui->tw_LogTabs->currentWidget() == ui->tb_DataFlow && m_airspaceMonitor)
160  {
161  ui->le_CG->setText(
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)));
165 
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);
170 
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());
178 
179  ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
180  ui->le_SimulatorSpecific->home(false);
181 
182  const CClient client = m_airspaceMonitor->getClientOrDefaultForCallsign(m_callsign);
183  ui->le_GndFlag->setText(boolToYesNo(client.hasGndFlagCapability()));
184 
185  this->displayElevationRequestReceive();
186  this->displayLastInterpolation(sLog);
187  }
188  else if (ui->tw_LogTabs->currentWidget() == ui->tb_Loopback) { this->displayLoopback(); }
189  }
190 
191  void CInterpolationLogDisplay::getLogAmdDisplayLastInterpolation()
192  {
193  if (!this->canLog()) { return; }
194  const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
195  this->displayLastInterpolation(sLog);
196  }
197 
198  void CInterpolationLogDisplay::displayLastInterpolation(const SituationLog &sLog)
199  {
200  if (!this->checkLogPrerequisites()) { return; }
201 
202  ui->te_LastInterpolatedSituation->setText(sLog.situationCurrent.toQString(true));
203  ui->te_SituationChange->setText(sLog.change.toQString(true));
204 
205  ui->le_SceneryOffset->setText(
206  sLog.change.getGuessedSceneryDeviation().valueRoundedWithUnit(CLengthUnit::ft(), 1));
207  ui->le_SceneryOffsetCG->setText(
208  sLog.change.getGuessedSceneryDeviationCG().valueRoundedWithUnit(CLengthUnit::ft(), 1));
209 
210  const PartsLog pLog = m_simulator->interpolationLogger().getLastPartsLog();
211  ui->te_LastInterpolatedParts->setText(pLog.parts.toQString(true));
212  }
213 
214  void CInterpolationLogDisplay::displayLoopback()
215  {
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);
219  }
220 
221  void CInterpolationLogDisplay::onSliderChanged(int timeSecs)
222  {
223  m_updateTimer.setInterval(timeSecs * 1000);
224  ui->le_UpdateTime->setText(QStringLiteral("%1secs").arg(timeSecs));
225  }
226 
227  void CInterpolationLogDisplay::onCallsignEntered()
228  {
229  if (!this->canLog())
230  {
231  this->stop();
232  CLogMessage(this).warning(u"Stopping logging (log.display), no simulator");
233  return;
234  }
235 
236  const CCallsign cs = ui->comp_CallsignCompleter->getCallsign();
237  if (m_callsign == cs) { return; }
238 
239  // empty callsign, just stop
240  if (cs.isEmpty())
241  {
242  this->stop();
243  m_callsign.clear();
244  return;
245  }
246 
247  // clear last callsign
248  if (!m_callsign.isEmpty())
249  {
250  m_simulator->setLogInterpolation(false, m_callsign); // stop logging "old" callsign
251  m_callsign.clear(); // clear callsign
252  this->clear();
253  }
254 
255  // set new callsign or stop
256  m_callsign = cs;
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;
261  }
262 
263  void CInterpolationLogDisplay::onPseudoElevationToggled(bool checked)
264  {
265  if (!this->canLog()) { return; }
266  m_simulator->setTestEnablePseudoElevation(checked);
267 
268  CAltitude elvTest = CAltitude::null();
269  if (!ui->le_ElevationTestValue->text().isEmpty())
270  {
271  CLength l;
272  const QString v = ui->le_ElevationTestValue->text();
273  l.parseFromString(v);
274  if (!l.isNull()) { elvTest = CAltitude(l, CAltitude::MeanSeaLevel); }
275  }
276  m_simulator->setTestElevation(elvTest);
277  }
278 
279  void CInterpolationLogDisplay::toggleStartStop()
280  {
281  const bool running = m_updateTimer.isActive();
282  m_callsign.clear(); // force update of data and log. start/stop
283  if (running) { this->stop(); }
284  else
285  {
286  // treat like a callsign was entered
287  this->onCallsignEntered();
288  }
289  }
290 
291  void CInterpolationLogDisplay::followInSimulator()
292  {
293  if (m_callsign.isEmpty()) { return; }
294  if (!this->canLog()) { return; }
295  m_simulator->followAircraft(m_callsign);
296  }
297 
298  bool CInterpolationLogDisplay::start()
299  {
300  if (m_updateTimer.isActive()) { return false; }
301 
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);
306 
307  this->initPartsView();
308  return true;
309  }
310 
311  void CInterpolationLogDisplay::stop()
312  {
313  m_updateTimer.stop();
314  ui->pb_StartStop->setText(startText());
315  ui->led_Running->setOn(false);
316  }
317 
318  bool CInterpolationLogDisplay::logCallsign(const CCallsign &cs) const
319  {
320  if (!sGui || sGui->isShuttingDown()) { return false; }
321  if (!m_airspaceMonitor || !m_simulator || m_callsign.isEmpty()) { return false; }
322  if (cs != m_callsign) { return false; }
323  return true;
324  }
325 
326  void CInterpolationLogDisplay::onAboutToShutdown()
327  {
328  m_updateTimer.stop();
329  m_simulator = nullptr;
330  }
331 
332  void CInterpolationLogDisplay::onSimulatorUnloaded()
333  {
334  m_updateTimer.stop();
335  m_simulator = nullptr;
336  this->resetStatistics();
337  }
338 
339  void CInterpolationLogDisplay::onSimulatorStatusChanged(ISimulator::SimulatorStatus status)
340  {
341  Q_UNUSED(status)
342  m_updateTimer.stop();
343  this->resetStatistics();
344  }
345 
346  void CInterpolationLogDisplay::onSituationAdded(const CAircraftSituation &situation)
347  {
348  static const QString info("times: %1 offset %2");
349 
350  const CCallsign cs = situation.getCallsign();
351  if (!this->logCallsign(cs)) { return; }
352  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(cs);
353  const MillisecondsMinMaxMean tsDiffMsMinMaxMean = situations.getTimestampDifferenceMinMaxMean();
354  const MillisecondsMinMaxMean offsetMsMinMaxMean = situations.getOffsetMinMaxMean();
355  const CAircraftSituationChangeList changes = m_airspaceMonitor->remoteAircraftSituationChanges(cs);
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();
360  }
361 
362  void CInterpolationLogDisplay::onPartsAdded(const CCallsign &callsign, const CAircraftParts &parts)
363  {
364  if (!this->logCallsign(callsign)) { return; }
365  Q_UNUSED(parts)
366  const CAircraftPartsList partsList = m_airspaceMonitor->remoteAircraftParts(callsign);
367  ui->tvp_InboundAircraftParts->updateContainerAsync(partsList);
368  ui->led_Parts->blink();
369  }
370 
371  void CInterpolationLogDisplay::onElevationReceived(const CElevationPlane &elevationPlane, const CCallsign &callsign)
372  {
373  m_elvReceived++;
374  if (m_elvHistoryCount > 0)
375  {
376  const QString history = callsign.asString() % QStringLiteral(": ") %
377  QTime::currentTime().toString("hh:mm:ss.zzz") % QStringLiteral(" ") %
378  elevationPlane.toQString(true);
379  m_elvHistoryModel->insertRow(0);
380  const QModelIndex index = m_elvHistoryModel->index(0, 0);
381  m_elvHistoryModel->setData(index, history);
382 
383  const int c = m_elvHistoryModel->rowCount();
384  if (m_elvHistoryCount < c) { m_elvHistoryModel->removeRows(m_elvHistoryCount, c - m_elvHistoryCount); }
385  }
386 
387  // not for a real plane, but to get elevation at any position for testing
388  if (callsign == CInterpolationLogDisplay::pseudoCallsignElevation())
389  {
390  this->displayArbitraryElevation(elevationPlane);
391  return;
392  }
393 
394  if (!this->logCallsign(callsign)) { return; }
395 
396  // for logged callsign
397  m_elvReceivedLoggedCs++;
398  ui->le_Elevation->setText(elevationPlane.toQString());
399  this->displayElevationRequestReceive();
400  ui->led_Elevation->blink();
401  }
402 
403  void CInterpolationLogDisplay::onElevationRequested(const CCallsign &callsign)
404  {
405  m_elvRequested++;
406  if (!this->logCallsign(callsign)) { return; }
407 
408  // for logged callsign
409  m_elvRequestedLoggedCs++;
410  this->displayElevationRequestReceive();
411  ui->led_Elevation->blink();
412  }
413 
414  void CInterpolationLogDisplay::onInjectElevation()
415  {
416  if (!this->canLog()) { return; }
417  const QString elv = ui->le_InjectElevation->text().trimmed();
418  if (elv.isEmpty()) { return; }
419 
420  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(m_callsign);
421  if (situations.isEmpty()) { return; }
422 
423  CAltitude alt;
424  alt.parseFromString(elv, CPqString::SeparatorBestGuess);
425  const CElevationPlane ep(situations.latestAdjustedObject(), alt, CElevationPlane::singlePointRadius());
426 
427  // inject as received from simulator
428  m_simulator->callbackReceivedRequestedElevation(ep, m_callsign, false);
429  }
430 
431  void CInterpolationLogDisplay::onElevationHistoryCountFinished()
432  {
433  const QString cs = ui->le_ElvHistoryCount->text().trimmed();
434  int c = -1;
435  if (!cs.isEmpty())
436  {
437  bool ok = false;
438  const int cc = cs.toInt(&ok);
439  if (ok) { c = cc; }
440  }
441  m_elvHistoryCount = c;
442  }
443 
444  void CInterpolationLogDisplay::resetStatistics()
445  {
446  if (m_simulator) { m_simulator->resetAircraftStatistics(); }
447  }
448 
449  void CInterpolationLogDisplay::resetLastSentValues()
450  {
451  if (m_simulator) { m_simulator->resetLastSentValues(); }
452  }
453 
454  void CInterpolationLogDisplay::clear()
455  {
456  ui->tvp_InboundAircraftParts->clear();
457  ui->tvp_InboundAircraftSituations->clear();
458  ui->te_TextLog->clear();
459  ui->le_CG->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();
470 
471  this->clearElevationResults();
472  }
473 
474  void CInterpolationLogDisplay::clearElevationResults()
475  {
476  ui->pte_ElevationAtPosition->clear();
477  if (m_elvHistoryModel) { m_elvHistoryModel->removeRows(0, m_elvHistoryModel->rowCount()); }
478  }
479 
480  void CInterpolationLogDisplay::logPosCommand()
481  {
482  if (m_callsign.isEmpty()) { return; }
483  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
484 
485  const QString cmd = QStringLiteral(".drv logint clear") % m_callsign.asString();
487  }
488 
489  void CInterpolationLogDisplay::clearLogCommand()
490  {
491  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
492 
493  const QString cmd = QStringLiteral(".drv logint clear");
495  }
496 
497  void CInterpolationLogDisplay::writeLogCommand()
498  {
499  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
500 
501  const QString cmd = QStringLiteral(".drv logint write");
503  }
504 
505  bool CInterpolationLogDisplay::checkLogPrerequisites()
506  {
507  using namespace std::chrono_literals;
508  CStatusMessage m;
509  do {
510  if (!this->isVisible()) { return false; } // silently return
511  if (!sGui || sGui->isShuttingDown()) { break; } // stop and return
512  if (m_callsign.isEmpty())
513  {
514  // static const CStatusMessage ms = CStatusMessage(this).validationError(u"No callsign for logging");
515  // m = ms;
516  break;
517  }
518 
519  const bool canUpdateLog =
520  m_airspaceMonitor && m_simulator && m_simulator->isConnected() && !m_simulator->isShuttingDown();
521  if (!canUpdateLog)
522  {
523  static const CStatusMessage ms =
524  CStatusMessage(this).validationError(u"No airspace monitor or simulator or shutting down");
525  m = ms;
526  break;
527  }
528 
529  if (!m_simulator->isLogCallsign(m_callsign))
530  {
531  m = CStatusMessage(this).validationError(u"No longer logging callsign '%1'") << m_callsign;
532  break;
533  }
534  return true;
535  }
536  while (false);
537 
538  this->stop();
539  if (!m.isEmpty()) { this->showOverlayMessage(m, 5s); }
540  return false;
541  }
542 
543  void CInterpolationLogDisplay::initPartsView()
544  {
545  // it can take a while until we receive parts, so we init
546  QPointer<CInterpolationLogDisplay> myself(this);
547  QTimer::singleShot(250, this, [=] {
548  if (!myself) { return; }
549  if (m_callsign.isEmpty()) { return; }
550  myself->onPartsAdded(m_callsign, CAircraftParts());
551  });
552  }
553 
554  void CInterpolationLogDisplay::displayElevationRequestReceive()
555  {
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)
561  .arg(m_elvRequested)
562  .arg(m_elvReceivedLoggedCs)
563  .arg(m_elvReceived)
564  .arg(foundMissed, reqTimes);
565 
566  ui->le_ElevationReqRec->setText(reqRec);
567  ui->le_ElevationReqRec->setToolTip(reqRec);
568  ui->le_ElevationReqRec->home(false);
569  }
570 
571  void CInterpolationLogDisplay::displayArbitraryElevation(const CElevationPlane &elevation)
572  {
573  ui->pte_ElevationAtPosition->appendPlainText(elevation.toQString());
574  }
575 
576  void CInterpolationLogDisplay::requestElevationClicked()
577  {
578  if (m_callsign.isEmpty()) { return; }
579  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(m_callsign);
580  if (situations.isEmpty()) { return; }
581  this->requestElevation(situations.latestAdjustedObject());
582  }
583 
584  void CInterpolationLogDisplay::requestElevation(const CAircraftSituation &situation)
585  {
586  if (!this->canLog()) { return; }
587  m_simulator->requestElevationBySituation(situation);
588  }
589 
590  void CInterpolationLogDisplay::requestElevationAtPosition()
591  {
592  if (!this->canLog()) { return; }
593  const CCoordinateGeodetic coordinate = ui->editor_ElevationCoordinate->getCoordinate();
594  const bool ok = m_simulator->requestElevation(coordinate, CInterpolationLogDisplay::pseudoCallsignElevation());
595  if (ok)
596  {
597  static const QString info("Requesting elevation: %1");
598  ui->pte_ElevationAtPosition->setPlainText(info.arg(coordinate.toQString()));
599  }
600  else
601  {
602  static const QString info("Cannot request elevation");
603  ui->pte_ElevationAtPosition->setPlainText(info);
604  }
605  }
606 
607  void CInterpolationLogDisplay::requestRecalculateAll()
608  {
609  if (!this->canLog()) { return; }
611  }
612 
613  bool CInterpolationLogDisplay::canLog() const
614  {
615  return (sApp && !sApp->isShuttingDown() && sApp->getIContextSimulator() && m_simulator);
616  }
617 
618  const CCallsign &CInterpolationLogDisplay::pseudoCallsignElevation()
619  {
620  static const CCallsign cs("SW1LOX");
621  return cs;
622  }
623 
625  {
626  if (!sGui || sGui->isShuttingDown() || !sGui->supportsContexts()) { return; }
627  if (!sGui->getCoreFacade() || !sGui->getCoreFacade()->getCContextNetwork()) { return; }
629  this->setAirspaceMonitor(cn->airspace());
630  }
631 
632  const QString &CInterpolationLogDisplay::startText()
633  {
634  static const QString start("start");
635  return start;
636  }
637 
638  const QString &CInterpolationLogDisplay::stopText()
639  {
640  static const QString stop("stop");
641  return stop;
642  }
643 } // namespace swift::gui::components
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
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.
Definition: application.h:346
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.
Definition: corefacade.cpp:487
Interface to a simulator.
Definition: simulator.h:59
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.
LedShape
Shapes.
Definition: led.h:51
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.
void setSimulator(swift::core::ISimulator *simulator)
Set simulator.
void setAirspaceMonitor(swift::core::CAirspaceMonitor *airspaceMonitor)
Set corresponding airspace monitor.
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...
Definition: identifiable.h:24
const CIdentifier & identifier() const
Get identifier.
Definition: identifiable.h:27
static const QString & interpolator()
Interpolator.
Definition: logcategories.h:73
static const QString & driver()
Driver.
Class for emitting a log message.
Definition: logmessage.h:27
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.
Definition: sequence.h:288
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
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.
Definition: aircraftparts.h:26
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.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
void parseFromString(const QString &value)
Parse value from string.
Definition: altitude.cpp:140
Value object encapsulating information of a callsign.
Definition: callsign.h:30
void clear()
Clear this callsign.
Definition: callsign.cpp:45
const QString & asString() const
Get callsign (normalized)
Definition: callsign.h:96
bool isEmpty() const
Is empty?
Definition: callsign.h:63
Plane of same elevation, can be a single point or larger area (e.g. airport)
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Another client software.
Definition: client.h:27
bool hasGndFlagCapability() const
Supports gnd.flag?
Definition: client.cpp:68
Physical unit length (length)
Definition: length.h:18
void parseFromString(const QString &value)
Parse value from string.
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.
Definition: actionbind.cpp:7
High level reusable GUI components.
Definition: aboutdialog.cpp:13
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...
Definition: threadutils.h:30
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