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  {
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,
99  }
100 
102 
104  {
105  if (simulator && simulator == m_simulator) { return; } // same
106  if (m_simulator)
107  {
108  this->disconnect(m_simulator);
109  m_simulator->disconnect(this);
110  }
111  m_simulator = simulator;
112  if (!simulator) { return; }
113  connect(m_simulator, &ISimulator::receivedRequestedElevation, this,
114  &CInterpolationLogDisplay::onElevationReceived, Qt::QueuedConnection);
115  connect(m_simulator, &ISimulator::requestedElevation, this, &CInterpolationLogDisplay::onElevationRequested,
117  connect(m_simulator, &ISimulator::destroyed, this, &CInterpolationLogDisplay::onSimulatorUnloaded);
118  connect(m_simulator, &ISimulator::simulatorStatusChanged, this,
119  &CInterpolationLogDisplay::onSimulatorStatusChanged);
120  }
121 
123  {
124  if (airspaceMonitor && airspaceMonitor == m_airspaceMonitor) { return; } // same
125  if (m_airspaceMonitor)
126  {
127  this->disconnect(m_airspaceMonitor);
128  m_airspaceMonitor->disconnect(this);
129  }
130  m_airspaceMonitor = airspaceMonitor;
131 
132  connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftSituation, this,
133  &CInterpolationLogDisplay::onSituationAdded, Qt::QueuedConnection);
134  connect(m_airspaceMonitor, &CAirspaceMonitor::addedAircraftParts, this, &CInterpolationLogDisplay::onPartsAdded,
136  }
137 
138  void CInterpolationLogDisplay::updateLog()
139  {
140  ui->led_Updating->blink(250);
141  if (!this->checkLogPrerequisites())
142  {
143  ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
144  return;
145  }
146 
147  const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
148  m_lastInterpolations.push_frontKeepLatestAdjustedFirst(sLog.situationCurrent, true, 10);
149 
150  // only display visible tab
151  if (ui->tw_LogTabs->currentWidget() == ui->tb_TextLog)
152  {
153  const QString log = m_simulator->latestLoggedDataFormatted(m_callsign);
154  ui->te_TextLog->setText(log);
155  }
156  else if (ui->tw_LogTabs->currentWidget() == ui->tb_DataFlow && m_airspaceMonitor)
157  {
158  ui->le_CG->setText(
159  m_airspaceMonitor->getSimulatorCG(m_callsign).valueRoundedWithUnit(CLengthUnit::ft(), 1));
160  ui->le_CG->home(false);
161  ui->le_Parts->setText(boolToYesNo(m_airspaceMonitor->isRemoteAircraftSupportingParts(m_callsign)));
162 
163  static const QString msTimeStr("%1ms");
164  static const QString updateTimes("%1ms avg: %2ms max: %3ms");
165  const QString avgUpdateTimeRounded =
166  QString::number(m_simulator->getStatisticsAverageUpdateTimeMs(), 'f', 2);
167 
168  ui->le_UpdateTimes->setText(updateTimes.arg(m_simulator->getStatisticsCurrentUpdateTimeMs())
169  .arg(avgUpdateTimeRounded)
170  .arg(m_simulator->getStatisticsMaxUpdateTimeMs()));
171  ui->le_UpdateTimes->home(false);
172  ui->le_UpdateCount->setText(QString::number(m_simulator->getStatisticsUpdateRuns()));
173  ui->le_UpdateReqTime->setText(msTimeStr.arg(m_simulator->getStatisticsAircraftUpdatedRequestedDeltaMs()));
174  ui->le_Limited->setText(m_simulator->updateAircraftLimitationInfo());
175 
176  ui->le_SimulatorSpecific->setText(m_simulator->getStatisticsSimulatorSpecific());
177  ui->le_SimulatorSpecific->home(false);
178 
179  const CClient client = m_airspaceMonitor->getClientOrDefaultForCallsign(m_callsign);
180  ui->le_GndFlag->setText(boolToYesNo(client.hasGndFlagCapability()));
181 
182  this->displayElevationRequestReceive();
183  this->displayLastInterpolation(sLog);
184  }
185  else if (ui->tw_LogTabs->currentWidget() == ui->tb_Loopback) { this->displayLoopback(); }
186  }
187 
188  void CInterpolationLogDisplay::getLogAmdDisplayLastInterpolation()
189  {
190  if (!this->canLog()) { return; }
191  const SituationLog sLog = m_simulator->interpolationLogger().getLastSituationLog();
192  this->displayLastInterpolation(sLog);
193  }
194 
195  void CInterpolationLogDisplay::displayLastInterpolation(const SituationLog &sLog)
196  {
197  if (!this->checkLogPrerequisites()) { return; }
198 
199  ui->te_LastInterpolatedSituation->setText(sLog.situationCurrent.toQString(true));
200  ui->te_SituationChange->setText(sLog.change.toQString(true));
201 
202  ui->le_SceneryOffset->setText(
203  sLog.change.getGuessedSceneryDeviation().valueRoundedWithUnit(CLengthUnit::ft(), 1));
204  ui->le_SceneryOffsetCG->setText(
205  sLog.change.getGuessedSceneryDeviationCG().valueRoundedWithUnit(CLengthUnit::ft(), 1));
206 
207  const PartsLog pLog = m_simulator->interpolationLogger().getLastPartsLog();
208  ui->te_LastInterpolatedParts->setText(pLog.parts.toQString(true));
209  }
210 
211  void CInterpolationLogDisplay::displayLoopback()
212  {
213  if (!m_simulator || m_callsign.isEmpty()) { return; }
214  ui->tvp_LoopbackAircraftSituations->updateContainerAsync(m_simulator->getLoopbackSituations(m_callsign));
215  ui->tvp_InterpolatedAircraftSituations->updateContainerAsync(m_lastInterpolations);
216  }
217 
218  void CInterpolationLogDisplay::onSliderChanged(int timeSecs)
219  {
220  m_updateTimer.setInterval(timeSecs * 1000);
221  ui->le_UpdateTime->setText(QStringLiteral("%1secs").arg(timeSecs));
222  }
223 
224  void CInterpolationLogDisplay::onCallsignEntered()
225  {
226  if (!this->canLog())
227  {
228  this->stop();
229  CLogMessage(this).warning(u"Stopping logging (log.display), no simulator");
230  return;
231  }
232 
233  const CCallsign cs = ui->comp_CallsignCompleter->getCallsign();
234  if (m_callsign == cs) { return; }
235 
236  // empty callsign, just stop
237  if (cs.isEmpty())
238  {
239  this->stop();
240  m_callsign.clear();
241  return;
242  }
243 
244  // clear last callsign
245  if (!m_callsign.isEmpty())
246  {
247  m_simulator->setLogInterpolation(false, m_callsign); // stop logging "old" callsign
248  m_callsign.clear(); // clear callsign
249  this->clear();
250  }
251 
252  // set new callsign or stop
253  m_callsign = cs;
254  m_simulator->setLogInterpolation(true, cs);
255  ui->comp_Parts->setCallsign(cs);
256  if (!this->start()) { this->initPartsView(); }
257  CLogMessage(this).info(u"Starting logging (log.display) of '%1'") << m_callsign;
258  }
259 
260  void CInterpolationLogDisplay::onPseudoElevationToggled(bool checked)
261  {
262  if (!this->canLog()) { return; }
263  m_simulator->setTestEnablePseudoElevation(checked);
264 
265  CAltitude elvTest = CAltitude::null();
266  if (!ui->le_ElevationTestValue->text().isEmpty())
267  {
268  CLength l;
269  const QString v = ui->le_ElevationTestValue->text();
270  l.parseFromString(v);
271  if (!l.isNull()) { elvTest = CAltitude(l, CAltitude::MeanSeaLevel); }
272  }
273  m_simulator->setTestElevation(elvTest);
274  }
275 
276  void CInterpolationLogDisplay::toggleStartStop()
277  {
278  const bool running = m_updateTimer.isActive();
279  m_callsign.clear(); // force update of data and log. start/stop
280  if (running) { this->stop(); }
281  else
282  {
283  // treat like a callsign was entered
284  this->onCallsignEntered();
285  }
286  }
287 
288  void CInterpolationLogDisplay::followInSimulator()
289  {
290  if (m_callsign.isEmpty()) { return; }
291  if (!this->canLog()) { return; }
292  m_simulator->followAircraft(m_callsign);
293  }
294 
295  bool CInterpolationLogDisplay::start()
296  {
297  if (m_updateTimer.isActive()) { return false; }
298 
299  const int interval = 1000 * ui->hs_UpdateTime->value();
300  m_updateTimer.start(interval);
301  ui->pb_StartStop->setText(stopText());
302  ui->led_Running->setOn(true);
303 
304  this->initPartsView();
305  return true;
306  }
307 
308  void CInterpolationLogDisplay::stop()
309  {
310  m_updateTimer.stop();
311  ui->pb_StartStop->setText(startText());
312  ui->led_Running->setOn(false);
313  }
314 
315  bool CInterpolationLogDisplay::logCallsign(const CCallsign &cs) const
316  {
317  if (!sGui || sGui->isShuttingDown()) { return false; }
318  if (!m_airspaceMonitor || !m_simulator || m_callsign.isEmpty()) { return false; }
319  if (cs != m_callsign) { return false; }
320  return true;
321  }
322 
323  void CInterpolationLogDisplay::onAboutToShutdown()
324  {
325  m_updateTimer.stop();
326  m_simulator = nullptr;
327  }
328 
329  void CInterpolationLogDisplay::onSimulatorUnloaded()
330  {
331  m_updateTimer.stop();
332  m_simulator = nullptr;
333  this->resetStatistics();
334  }
335 
336  void CInterpolationLogDisplay::onSimulatorStatusChanged(ISimulator::SimulatorStatus status)
337  {
338  Q_UNUSED(status)
339  m_updateTimer.stop();
340  this->resetStatistics();
341  }
342 
343  void CInterpolationLogDisplay::onSituationAdded(const CAircraftSituation &situation)
344  {
345  static const QString info("times: %1 offset %2");
346 
347  const CCallsign cs = situation.getCallsign();
348  if (!this->logCallsign(cs)) { return; }
349  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(cs);
350  const MillisecondsMinMaxMean tsDiffMsMinMaxMean = situations.getTimestampDifferenceMinMaxMean();
351  const MillisecondsMinMaxMean offsetMsMinMaxMean = situations.getOffsetMinMaxMean();
352  const CAircraftSituationChangeList changes = m_airspaceMonitor->remoteAircraftSituationChanges(cs);
353  ui->tvp_InboundAircraftSituations->updateContainerAsync(situations);
354  ui->tvp_Changes->updateContainerMaybeAsync(changes);
355  ui->le_InboundSituationsInfo->setText(info.arg(tsDiffMsMinMaxMean.asString(), offsetMsMinMaxMean.asString()));
356  ui->led_Situation->blink();
357  }
358 
359  void CInterpolationLogDisplay::onPartsAdded(const CCallsign &callsign, const CAircraftParts &parts)
360  {
361  if (!this->logCallsign(callsign)) { return; }
362  Q_UNUSED(parts)
363  const CAircraftPartsList partsList = m_airspaceMonitor->remoteAircraftParts(callsign);
364  ui->tvp_InboundAircraftParts->updateContainerAsync(partsList);
365  ui->led_Parts->blink();
366  }
367 
368  void CInterpolationLogDisplay::onElevationReceived(const CElevationPlane &elevationPlane, const CCallsign &callsign)
369  {
370  m_elvReceived++;
371  if (m_elvHistoryCount > 0)
372  {
373  const QString history = callsign.asString() % QStringLiteral(": ") %
374  QTime::currentTime().toString("hh:mm:ss.zzz") % QStringLiteral(" ") %
375  elevationPlane.toQString(true);
376  m_elvHistoryModel->insertRow(0);
377  const QModelIndex index = m_elvHistoryModel->index(0, 0);
378  m_elvHistoryModel->setData(index, history);
379 
380  const int c = m_elvHistoryModel->rowCount();
381  if (m_elvHistoryCount < c) { m_elvHistoryModel->removeRows(m_elvHistoryCount, c - m_elvHistoryCount); }
382  }
383 
384  // not for a real plane, but to get elevation at any position for testing
385  if (callsign == CInterpolationLogDisplay::pseudoCallsignElevation())
386  {
387  this->displayArbitraryElevation(elevationPlane);
388  return;
389  }
390 
391  if (!this->logCallsign(callsign)) { return; }
392 
393  // for logged callsign
394  m_elvReceivedLoggedCs++;
395  ui->le_Elevation->setText(elevationPlane.toQString());
396  this->displayElevationRequestReceive();
397  ui->led_Elevation->blink();
398  }
399 
400  void CInterpolationLogDisplay::onElevationRequested(const CCallsign &callsign)
401  {
402  m_elvRequested++;
403  if (!this->logCallsign(callsign)) { return; }
404 
405  // for logged callsign
406  m_elvRequestedLoggedCs++;
407  this->displayElevationRequestReceive();
408  ui->led_Elevation->blink();
409  }
410 
411  void CInterpolationLogDisplay::onInjectElevation()
412  {
413  if (!this->canLog()) { return; }
414  const QString elv = ui->le_InjectElevation->text().trimmed();
415  if (elv.isEmpty()) { return; }
416 
417  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(m_callsign);
418  if (situations.isEmpty()) { return; }
419 
420  CAltitude alt;
421  alt.parseFromString(elv, CPqString::SeparatorBestGuess);
422  const CElevationPlane ep(situations.latestAdjustedObject(), alt, CElevationPlane::singlePointRadius());
423 
424  // inject as received from simulator
425  m_simulator->callbackReceivedRequestedElevation(ep, m_callsign, false);
426  }
427 
428  void CInterpolationLogDisplay::onElevationHistoryCountFinished()
429  {
430  const QString cs = ui->le_ElvHistoryCount->text().trimmed();
431  int c = -1;
432  if (!cs.isEmpty())
433  {
434  bool ok = false;
435  const int cc = cs.toInt(&ok);
436  if (ok) { c = cc; }
437  }
438  m_elvHistoryCount = c;
439  }
440 
441  void CInterpolationLogDisplay::resetStatistics()
442  {
443  if (m_simulator) { m_simulator->resetAircraftStatistics(); }
444  }
445 
446  void CInterpolationLogDisplay::resetLastSentValues()
447  {
448  if (m_simulator) { m_simulator->resetLastSentValues(); }
449  }
450 
451  void CInterpolationLogDisplay::clear()
452  {
453  ui->tvp_InboundAircraftParts->clear();
454  ui->tvp_InboundAircraftSituations->clear();
455  ui->te_TextLog->clear();
456  ui->le_CG->clear();
457  ui->le_Elevation->clear();
458  ui->le_ElevationReqRec->clear();
459  ui->le_ElevationReqRec->setToolTip("elevation requested");
460  ui->le_Parts->clear();
461  ui->le_UpdateTimes->clear();
462  ui->le_UpdateTimes->clear();
463  ui->le_Limited->clear();
464  m_elvReceivedLoggedCs = m_elvRequestedLoggedCs = 0;
465  m_elvReceived = m_elvRequested = 0;
466  m_lastInterpolations.clear();
467 
468  this->clearElevationResults();
469  }
470 
471  void CInterpolationLogDisplay::clearElevationResults()
472  {
473  ui->pte_ElevationAtPosition->clear();
474  if (m_elvHistoryModel) { m_elvHistoryModel->removeRows(0, m_elvHistoryModel->rowCount()); }
475  }
476 
477  void CInterpolationLogDisplay::logPosCommand()
478  {
479  if (m_callsign.isEmpty()) { return; }
480  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
481 
482  const QString cmd = QStringLiteral(".drv logint clear") % m_callsign.asString();
484  }
485 
486  void CInterpolationLogDisplay::clearLogCommand()
487  {
488  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
489 
490  const QString cmd = QStringLiteral(".drv logint clear");
492  }
493 
494  void CInterpolationLogDisplay::writeLogCommand()
495  {
496  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
497 
498  const QString cmd = QStringLiteral(".drv logint write");
500  }
501 
502  bool CInterpolationLogDisplay::checkLogPrerequisites()
503  {
504  using namespace std::chrono_literals;
505  CStatusMessage m;
506  do {
507  if (!this->isVisible()) { return false; } // silently return
508  if (!sGui || sGui->isShuttingDown()) { break; } // stop and return
509  if (m_callsign.isEmpty())
510  {
511  // static const CStatusMessage ms = CStatusMessage(this).validationError(u"No callsign for logging");
512  // m = ms;
513  break;
514  }
515 
516  const bool canUpdateLog =
517  m_airspaceMonitor && m_simulator && m_simulator->isConnected() && !m_simulator->isShuttingDown();
518  if (!canUpdateLog)
519  {
520  static const CStatusMessage ms =
521  CStatusMessage(this).validationError(u"No airspace monitor or simulator or shutting down");
522  m = ms;
523  break;
524  }
525 
526  if (!m_simulator->isLogCallsign(m_callsign))
527  {
528  m = CStatusMessage(this).validationError(u"No longer logging callsign '%1'") << m_callsign;
529  break;
530  }
531  return true;
532  }
533  while (false);
534 
535  this->stop();
536  if (!m.isEmpty()) { this->showOverlayMessage(m, 5s); }
537  return false;
538  }
539 
540  void CInterpolationLogDisplay::initPartsView()
541  {
542  // it can take a while until we receive parts, so we init
544  QTimer::singleShot(250, this, [=] {
545  if (!myself) { return; }
546  if (m_callsign.isEmpty()) { return; }
547  myself->onPartsAdded(m_callsign, CAircraftParts());
548  });
549  }
550 
551  void CInterpolationLogDisplay::displayElevationRequestReceive()
552  {
553  if (!m_airspaceMonitor) { return; }
554  static const QString info("req. %1, %2/rec. %3, %4 | found/missed: '%5' | times: %6");
555  const QString foundMissed = m_airspaceMonitor->getElevationsFoundMissedInfo();
556  const QString reqTimes = m_airspaceMonitor->getElevationRequestTimesInfo();
557  const QString reqRec = info.arg(m_elvRequestedLoggedCs)
558  .arg(m_elvRequested)
559  .arg(m_elvReceivedLoggedCs)
560  .arg(m_elvReceived)
561  .arg(foundMissed, reqTimes);
562 
563  ui->le_ElevationReqRec->setText(reqRec);
564  ui->le_ElevationReqRec->setToolTip(reqRec);
565  ui->le_ElevationReqRec->home(false);
566  }
567 
568  void CInterpolationLogDisplay::displayArbitraryElevation(const CElevationPlane &elevation)
569  {
570  ui->pte_ElevationAtPosition->appendPlainText(elevation.toQString());
571  }
572 
573  void CInterpolationLogDisplay::requestElevationClicked()
574  {
575  if (m_callsign.isEmpty()) { return; }
576  const CAircraftSituationList situations = m_airspaceMonitor->remoteAircraftSituations(m_callsign);
577  if (situations.isEmpty()) { return; }
578  this->requestElevation(situations.latestAdjustedObject());
579  }
580 
581  void CInterpolationLogDisplay::requestElevation(const CAircraftSituation &situation)
582  {
583  if (!this->canLog()) { return; }
584  m_simulator->requestElevationBySituation(situation);
585  }
586 
587  void CInterpolationLogDisplay::requestElevationAtPosition()
588  {
589  if (!this->canLog()) { return; }
590  const CCoordinateGeodetic coordinate = ui->editor_ElevationCoordinate->getCoordinate();
591  const bool ok = m_simulator->requestElevation(coordinate, CInterpolationLogDisplay::pseudoCallsignElevation());
592  if (ok)
593  {
594  static const QString info("Requesting elevation: %1");
595  ui->pte_ElevationAtPosition->setPlainText(info.arg(coordinate.toQString()));
596  }
597  else
598  {
599  static const QString info("Cannot request elevation");
600  ui->pte_ElevationAtPosition->setPlainText(info);
601  }
602  }
603 
604  void CInterpolationLogDisplay::requestRecalculateAll()
605  {
606  if (!this->canLog()) { return; }
608  }
609 
610  bool CInterpolationLogDisplay::canLog() const
611  {
612  return (sApp && !sApp->isShuttingDown() && sApp->getIContextSimulator() && m_simulator);
613  }
614 
615  const CCallsign &CInterpolationLogDisplay::pseudoCallsignElevation()
616  {
617  static const CCallsign cs("SW1LOX");
618  return cs;
619  }
620 
622  {
623  if (!sGui || sGui->isShuttingDown() || !sGui->supportsContexts()) { return; }
624  if (!sGui->getCoreFacade() || !sGui->getCoreFacade()->getCContextNetwork()) { return; }
626  this->setAirspaceMonitor(cn->airspace());
627  }
628 
629  const QString &CInterpolationLogDisplay::startText()
630  {
631  static const QString start("start");
632  return start;
633  }
634 
635  const QString &CInterpolationLogDisplay::stopText()
636  {
637  static const QString stop("stop");
638  return stop;
639  }
640 } // 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:481
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:74
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:14
Views, mainly QTableView.
Free functions in swift::misc.
void toggled(bool checked)
bool insertRow(int row, const QModelIndex &parent)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
void valueChanged(int value)
void editingFinished()
void returnPressed()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
int toInt(bool *ok, int base) const const
virtual bool removeRows(int row, int count, const QModelIndex &parent) override
virtual int rowCount(const QModelIndex &parent) const const override
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override
QueuedConnection
QTime currentTime()
QString toString(QStringView format) const const
void setInterval(int msec)
bool isActive() const const
void start()
void stop()
void timeout()
bool isVisible() const const
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