swift
simulatorcomponent.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include "ui_simulatorcomponent.h"
7 
10 #include "core/simulator.h"
11 #include "gui/guiapplication.h"
14 #include "misc/aviation/altitude.h"
16 #include "misc/aviation/heading.h"
17 #include "misc/geo/latitude.h"
18 #include "misc/geo/longitude.h"
19 #include "misc/iconlist.h"
20 #include "misc/pq/angle.h"
21 #include "misc/pq/frequency.h"
22 #include "misc/pq/speed.h"
25 #include "misc/stringutils.h"
26 
27 using namespace swift::misc;
28 using namespace swift::misc::aviation;
29 using namespace swift::misc::physical_quantities;
30 using namespace swift::misc::simulation;
31 using namespace swift::core;
32 using namespace swift::core::context;
33 
34 namespace swift::gui::components
35 {
36  const QStringList &CSimulatorComponent::getLogCategories()
37  {
38  static const QStringList cats { CLogCategories::guiComponent(), CLogCategories::matching() };
39  return cats;
40  }
41 
42  CSimulatorComponent::CSimulatorComponent(QWidget *parent)
43  : QTabWidget(parent), CEnableForDockWidgetInfoArea(), ui(new Ui::CSimulatorComponent)
44  {
45  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
46 
47  ui->setupUi(this);
48  this->setCurrentIndex(0);
49  ui->comp_StatusMessages->showFilterDialog();
50 
51  // live data and internals
52  ui->tvp_LiveData->setIconMode(true);
53  ui->tvp_LiveData->setAutoResizeFrequency(10); // only resize every n-th time
54  ui->tvp_Internals->setIconMode(false);
55  this->addOrUpdateLiveDataByName("info", "no data yet", CIcons::StandardIconWarning16);
56 
57  // connects
58  connect(sGui->getIContextSimulator(), &IContextSimulator::simulatorStatusChanged, this,
59  &CSimulatorComponent::onSimulatorStatusChanged, Qt::QueuedConnection);
60  connect(&m_updateTimer, &QTimer::timeout, this, &CSimulatorComponent::update);
61  connect(ui->pb_RefreshInternals, &QPushButton::pressed, this, &CSimulatorComponent::refreshInternals);
63  {
64  connect(sGui->getIContextSimulator(), &IContextSimulator::addingRemoteModelFailed, this,
65  &CSimulatorComponent::onAddingRemoteModelFailed, Qt::QueuedConnection);
66  connect(sGui->getIContextSimulator(), &IContextSimulator::driverMessages, this,
67  &CSimulatorComponent::onSimulatorMessages, Qt::QueuedConnection);
68  }
69 
70  // init status
71  this->onSimulatorStatusChanged(sGui->getIContextSimulator()->getSimulatorStatus());
72  }
73 
75 
76  void CSimulatorComponent::addOrUpdateLiveDataByName(const QString &name, const QString &value, const CIcon &icon)
77  {
78  const bool resize = this->currentWidget() == ui->tb_LiveData; // simulator live data selected?
79  ui->tvp_LiveData->addOrUpdateByName(name, value, icon, resize, false);
80  }
81 
82  void CSimulatorComponent::addOrUpdateLiveDataByName(const QString &name, const QString &value,
83  CIcons::IconIndex iconIndex)
84  {
85  this->addOrUpdateLiveDataByName(name, value, CIcon::iconByIndex(iconIndex));
86  }
87 
88  void CSimulatorComponent::removeLiveDataByName(const QString &name) { ui->tvp_LiveData->removeByName(name); }
89 
90  int CSimulatorComponent::rowCount() const { return ui->tvp_LiveData->rowCount(); }
91 
92  void CSimulatorComponent::clear(bool addInternalsAfterwards)
93  {
94  ui->tvp_LiveData->clear();
95  if (addInternalsAfterwards) { this->refreshInternals(); }
96  }
97 
99  {
100  if (!this->isVisibleWidget()) return; // no updates on invisible widgets
101  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextOwnAircraft()) return;
102 
103  const ISimulator::SimulatorStatus simulatorStatus =
104  static_cast<ISimulator::SimulatorStatus>(sGui->getIContextSimulator()->getSimulatorStatus());
105  if (simulatorStatus == ISimulator::Unspecified || simulatorStatus == ISimulator::Disconnected)
106  {
107  static const QString s("No simulator available");
108  this->addOrUpdateLiveDataByName(QStringLiteral("info"), s, CIcons::StandardIconWarning16);
109  return;
110  }
111 
112  if (!simulatorStatus.testFlag(ISimulator::Simulating))
113  {
114  static const QString s("Simulator (%1) not yet running");
115  this->addOrUpdateLiveDataByName(
116  QStringLiteral("info"), s.arg(sGui->getIContextSimulator()->getSimulatorPluginInfo().getSimulator()),
117  CIcons::StandardIconWarning16);
118  return;
119  }
120 
121  // clear old warnings / information
122  if (this->rowCount() < 5) { this->clear(true); }
123 
125  const CAircraftSituation s = ownAircraft.getSituation();
126  const CComSystem c1 = ownAircraft.getCom1System();
127  const CComSystem c2 = ownAircraft.getCom2System();
128  static const CIcon iconAlt(s.getAltitude().toIcon()); // minor performance improvement
129  static const CIcon iconLatLng(s.latitude().toIcon());
130  static const CIcon iconRadio(CIcon::iconByIndex(CIcons::StandardIconRadio16));
131  static const CIcon iconAttitude(CIcon::iconByIndex(CIcons::AviationAttitudeIndicator));
132  static const CIcon iconPlane(CIcon::iconByIndex(CIcons::StandardIconPaperPlane16));
133 
134  if (m_simulator.isAnySimulator())
135  {
136  this->addOrUpdateLiveDataByName("simulator", m_simulator.toQString(true), m_simulator.toIcon());
137 
138  if (sGui->getISimulator())
139  {
140  const double fps = sGui->getISimulator()->getAverageFPS();
141  this->addOrUpdateLiveDataByName(QStringLiteral("FPS"),
142  fps < 0 ? QStringLiteral("N/A") : QString::number(fps, 'f', 1),
143  CIcon(CIcons::ApplicationSimulator));
144 
145  const double ratio = sGui->getISimulator()->getSimTimeRatio();
146  this->addOrUpdateLiveDataByName(QStringLiteral("Time Ratio"), QString::number(ratio, 'f', 2),
147  CIcon(CIcons::ApplicationSimulator));
148 
149  const double miles = sGui->getISimulator()->getTrackMilesShort();
150  this->addOrUpdateLiveDataByName(QStringLiteral("Miles Short"), QString::number(miles, 'f', 1),
151  CIcon(CIcons::ApplicationSimulator));
152 
153  const double minutes = sGui->getISimulator()->getMinutesLate();
154  this->addOrUpdateLiveDataByName(QStringLiteral("Minutes Late"), QString::number(minutes, 'f', 1),
155  CIcon(CIcons::ApplicationSimulator));
156  }
157  }
158 
159  this->addOrUpdateLiveDataByName(QStringLiteral("latitude"), s.latitude().toQString(), iconLatLng);
160  this->addOrUpdateLiveDataByName(QStringLiteral("longitude"), s.longitude().toQString(), iconLatLng);
161  this->addOrUpdateLiveDataByName(QStringLiteral("altitude, true (ft)"),
162  s.getAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1), iconAlt);
163  this->addOrUpdateLiveDataByName(QStringLiteral("altitude, true (m)"),
164  s.getAltitude().valueRoundedWithUnit(CLengthUnit::m(), 2), iconAlt);
165  this->addOrUpdateLiveDataByName(QStringLiteral("altitude, pressure (ft)"),
166  s.getPressureAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1), iconAlt);
167  this->addOrUpdateLiveDataByName(QStringLiteral("altitude, pressure (m)"),
168  s.getPressureAltitude().valueRoundedWithUnit(CLengthUnit::m(), 2), iconAlt);
169 
170  if (s.hasGroundElevation())
171  {
172  this->addOrUpdateLiveDataByName(QStringLiteral("elevation (ft)"),
173  s.getGroundElevation().valueRoundedWithUnit(CLengthUnit::ft(), 1), iconAlt);
174  this->addOrUpdateLiveDataByName(QStringLiteral("elevation (m)"),
175  s.getGroundElevation().valueRoundedWithUnit(CLengthUnit::m(), 2), iconAlt);
176  }
177  else { this->addOrUpdateLiveDataByName(QStringLiteral("elevation"), QStringLiteral("N/A"), iconAlt); }
178 
179  if (ownAircraft.hasCG())
180  {
181  this->addOrUpdateLiveDataByName(QStringLiteral("CG (ft)"),
182  ownAircraft.getCG().valueRoundedWithUnit(CLengthUnit::ft(), 1), iconPlane);
183  this->addOrUpdateLiveDataByName(QStringLiteral("CG (m)"),
184  ownAircraft.getCG().valueRoundedWithUnit(CLengthUnit::m(), 2), iconPlane);
185  }
186  else { this->addOrUpdateLiveDataByName(QStringLiteral("CG"), QStringLiteral("N/A"), iconPlane); }
187 
188  this->addOrUpdateLiveDataByName(QStringLiteral("pitch"), s.getPitch().toQString(), iconAttitude);
189  this->addOrUpdateLiveDataByName(QStringLiteral("bank"), s.getBank().toQString(), iconAttitude);
190 
191  const CHeading heading = s.getHeading().normalizedTo360Degrees();
192  this->addOrUpdateLiveDataByName(QStringLiteral("heading"), heading.valueRoundedWithUnit(CAngleUnit::deg(), 1),
193  s.getHeading().toIcon());
194 
195  const CSpeed gs = s.getGroundSpeed();
196  this->addOrUpdateLiveDataByName(QStringLiteral("ground speed (kts)"),
197  gs.valueRoundedWithUnit(CSpeedUnit::kts(), 1), gs.toIcon());
198  this->addOrUpdateLiveDataByName(QStringLiteral("ground speed (km/h)"),
199  gs.valueRoundedWithUnit(CSpeedUnit::km_h(), 1), gs.toIcon());
200 
201  this->addOrUpdateLiveDataByName(QStringLiteral("COM1 active"), c1.getFrequencyActive().toQString(), iconRadio);
202  this->addOrUpdateLiveDataByName(QStringLiteral("COM2 active"), c2.getFrequencyActive().toQString(), iconRadio);
203  this->addOrUpdateLiveDataByName(QStringLiteral("COM1 standby"), c1.getFrequencyStandby().toQString(),
204  iconRadio);
205  this->addOrUpdateLiveDataByName(QStringLiteral("COM2 standby"), c2.getFrequencyStandby().toQString(),
206  iconRadio);
207  this->addOrUpdateLiveDataByName(QStringLiteral("COM1 volume"), QString::number(c1.getVolumeReceive()),
208  iconRadio);
209  this->addOrUpdateLiveDataByName(QStringLiteral("COM2 volume"), QString::number(c2.getVolumeReceive()),
210  iconRadio);
211  this->addOrUpdateLiveDataByName(QStringLiteral("Transponder"), ownAircraft.getTransponderCodeFormatted(),
212  iconRadio);
213  }
214 
215  void CSimulatorComponent::onSimulatorStatusChanged(int status)
216  {
217  ISimulator::SimulatorStatus simStatus = static_cast<ISimulator::SimulatorStatus>(status);
218  this->clear(); // clean up, will be refreshed
219  if (simStatus.testFlag(ISimulator::Connected))
220  {
221  const int intervalMs = getUpdateIntervalMs();
222  m_updateTimer.start(intervalMs);
223  this->clear(true);
224  }
225  else
226  {
227  m_updateTimer.stop();
228  this->update();
229  }
230  }
231 
232  void CSimulatorComponent::onAddingRemoteModelFailed(const CSimulatedAircraft &aircraft, bool disabled,
233  bool failover, const CStatusMessage &message)
234  {
235  const CStatusMessage msg =
236  CStatusMessage(this).warning(u"Adding model '%1' failed, disabled: %2: failover: %3 details: %4")
237  << aircraft.getModelString() << boolToYesNo(disabled) << boolToYesNo(failover) << aircraft.toQString(true);
238  ui->comp_StatusMessages->appendStatusMessageToList(msg);
239  ui->comp_StatusMessages->appendStatusMessageToList(message);
240  }
241 
242  void CSimulatorComponent::onSimulatorMessages(const CStatusMessageList &messages)
243  {
244  if (messages.isEmpty()) { return; }
245  ui->comp_StatusMessages->appendStatusMessagesToList(messages);
246  }
247 
248  void CSimulatorComponent::refreshInternals()
249  {
250  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextSimulator()) { return; }
253  m_simulator = simulatorInfo;
254 
255  const QStringList names(internals.getSortedNames());
256  if (names.isEmpty())
257  {
258  ui->tvp_Internals->clear();
259  return;
260  }
261 
262  // Update the INTERNAL view
263  static const CIcon emptyIcon;
264  const bool resize = true;
265  const bool skipEqualValues = true;
266  for (const QString &name : names)
267  {
268  ui->tvp_Internals->addOrUpdateByName(name, internals.getVariantValue(name), emptyIcon, resize,
269  skipEqualValues);
270  }
271  ui->tvp_Internals->fullResizeToContents();
272  }
273 
274  int CSimulatorComponent::getUpdateIntervalMs() const
275  {
276  // much slower updates via DBus
277  if (!sGui || sGui->isShuttingDown()) { return 10000; }
278  return sGui->getIContextSimulator()->isUsingImplementingObject() ? 1000 : 5000;
279  }
280 } // namespace swift::gui::components
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
QPointer< ISimulator > getISimulator() const
The simulator plugin, if available.
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.
bool isUsingImplementingObject() const
Using local implementing object?
Definition: context.h:45
virtual swift::misc::simulation::CSimulatedAircraft getOwnAircraft() const =0
Get own aircraft.
virtual swift::misc::simulation::CSimulatorPluginInfo getSimulatorPluginInfo() const =0
Simulator info, currently loaded plugin.
virtual swift::misc::simulation::CSimulatorInternals getSimulatorInternals() const =0
Simulator setup.
virtual ISimulator::SimulatorStatus getSimulatorStatus() const =0
Simulator combined status.
Helper class: If a component is residing in an dockable widget. This class provides access to its inf...
void clear(bool addInternalsAfterwards=false)
Clear.
Value object for icons. An icon is stored in the global icon repository and identified by its index....
Definition: icon.h:39
IconIndex
Index for each icon, allows to send them via DBus, efficiently store them, etc.
Definition: icons.h:32
static const QString & matching()
Matching.
static const QString & guiComponent()
GUI components.
Definition: logcategories.h:94
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
Value object encapsulating information of an aircraft's situation.
const CAltitude & getGroundElevation() const
Elevation of the ground directly beneath.
bool hasGroundElevation() const
Is ground elevation value available.
const CHeading & getHeading() const
Get heading.
virtual geo::CLatitude latitude() const
Latitude.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
const CAltitude & getAltitude() const
Get altitude.
const CAltitude & getPressureAltitude() const
Get pressure altitude.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
const physical_quantities::CAngle & getPitch() const
Get pitch.
virtual geo::CLongitude longitude() const
Longitude.
swift::misc::CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
Definition: altitude.cpp:397
COM system (aka "radio")
Definition: comsystem.h:37
Heading as used in aviation, can be true or magnetic heading.
Definition: heading.h:41
CHeading normalizedTo360Degrees() const
As [0, 359.99] normalized heading.
Definition: heading.cpp:46
swift::misc::physical_quantities::CFrequency getFrequencyStandby() const
Standby frequency.
Definition: modulator.cpp:36
int getVolumeReceive() const
Output volume 0..100.
Definition: modulator.cpp:54
swift::misc::physical_quantities::CFrequency getFrequencyActive() const
Active frequency.
Definition: modulator.cpp:30
CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
Definition: earthangle.cpp:156
CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
Definition: mixinicon.h:39
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
swift::misc::CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
Definition: angle.cpp:42
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".
Comprehensive information of an aircraft.
const aviation::CAircraftSituation & getSituation() const
Get situation.
const aviation::CComSystem & getCom2System() const
Get COM2 system.
QString getTransponderCodeFormatted() const
Get transponder code.
const aviation::CComSystem & getCom1System() const
Get COM1 system.
const physical_quantities::CLength & getCG() const
Get CG from model.
const QString & getModelString() const
Get model string.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
bool isAnySimulator() const
Any simulator?
Simulator internals for flight simulators. Those are obtained from a running simulator and represent ...
QStringList getSortedNames() const
Get sorted names.
CVariant getVariantValue(const QString &name) const
Get value.
const QString & getSimulator() const
Simulator.
const CSimulatorInfo & getSimulatorInfo() const
Simulator info object.
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
Free functions in swift::misc.