Newer
Older
/****************************************************************************
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
dogmaphobic
committed
*
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#include <QAction>
#include <QDesktopWidget>
#include <QPainter>
#include <QPixmap>
#include <QQuickImageProvider>
#include <QQuickStyle>
#include <QQuickWindow>
#include <QRegularExpression>
#include <QStringListModel>
#include <QStyleFactory>
#ifdef QGC_ENABLE_BLUETOOTH
#include <QBluetoothLocalDevice>
#endif
#if defined(QGC_GST_STREAMING)
#include "GStreamer.h"
#endif
#include "FlightMapSettings.h"
#include "FlightPathSegment.h"
#include "JoystickManager.h"
#include "LinkManager.h"
#include "LogDownloadController.h"
#include "MultiVehicleManager.h"
#include "ParameterEditorController.h"
#include "PlanMasterController.h"
#include "QGC.h"
#include "QGCApplication.h"
#include "QGCFileDialogController.h"
#include "QGCGeoBoundingCube.h"
#include "QGCLoggingCategory.h"
#include "QGCMapPalette.h"
#include "QGCPalette.h"
#include "QGCTemporaryFile.h"
#include "QGroundControlQmlGlobal.h"
#include "QmlObjectListModel.h"
#include "RCChannelMonitorController.h"
#include "ScreenToolsController.h"
#include "SyslinkComponentController.h"
#include "UASMessageHandler.h"
#include "UDPLink.h"
#include "Vehicle.h"
#include "VehicleComponent.h"
#include "VideoManager.h"
#include "VideoReceiver.h"
#if defined(QGC_ENABLE_MAVLINK_INSPECTOR)
#include "MAVLinkInspectorController.h"
#endif
#include "AppMessages.h"
#include "EditPositionDialogController.h"
#include "FactValueSliderListModel.h"
#include "HorizontalFactValueGrid.h"
#include "InstrumentValueData.h"
#include "MavlinkConsoleController.h"
#include "MissionCommandTree.h"
#include "ParameterManager.h"
#include "PositionManager.h"
#include "QGCCameraManager.h"
#include "QGCCorePlugin.h"
#include "QGCFileDownload.h"
#include "QGCMAVLink.h"
#include "QGCMapCircle.h"
#include "QGCMapPolygon.h"
#include "RCToParamDialogController.h"
#include "SettingsManager.h"
#include "ShapeFileHelper.h"
#include "SimulatedPosition.h"
#include "TerrainProfile.h"
#include "ToolStripAction.h"
#include "ToolStripActionList.h"
#include "VehicleObjectAvoidance.h"
#include "VisualMissionItem.h"
#include "AreaData.h"
#include "CircularGenerator.h"
#include "LinearGenerator.h"
#include "NemoInterface.h"
#if defined(QGC_ENABLE_PAIRING)
#include "PairingManager.h"
#endif
#ifndef __mobile__
#include "FirmwareUpgradeController.h"
#endif
#include "SerialLink.h"
#ifdef QGC_RTLAB_ENABLED
#endif
#ifdef Q_OS_LINUX
#ifndef __mobile__
#include <sys/types.h>
class FinishVideoInitialization : public QRunnable {
FinishVideoInitialization(VideoManager *manager) : _manager(manager) {}
void run() { _manager->_initVideo(); }
QGCApplication *QGCApplication::_app = nullptr;
const char *QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot";
const char *QGCApplication::_settingsVersionKey = "SettingsVersion";
// Mavlink status structures for entire app
mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
static QObject *screenToolsControllerSingletonFactory(QQmlEngine *,
QJSEngine *) {
ScreenToolsController *screenToolsController = new ScreenToolsController;
return screenToolsController;
static QObject *mavlinkSingletonFactory(QQmlEngine *, QJSEngine *) {
return new QGCMAVLink();
static QObject *qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine *,
QJSEngine *) {
// We create this object as a QGCTool even though it isn't in the toolbox
QGroundControlQmlGlobal *qmlGlobal =
new QGroundControlQmlGlobal(qgcApp(), qgcApp()->toolbox());
qmlGlobal->setToolbox(qgcApp()->toolbox());
static QObject *shapeFileHelperSingletonFactory(QQmlEngine *, QJSEngine *) {
return new ShapeFileHelper;
QObject *getNemoInterface(QQmlEngine *engine, QJSEngine *) {
engine->setObjectOwnership(pNemoInterface, QQmlEngine::CppOwnership);
return pNemoInterface;
}
QGCApplication::QGCApplication(int &argc, char *argv[], bool unitTesting)
: QApplication(argc, argv), _runningUnitTests(unitTesting) {
_app = this;
_msecsElapsedTime.start();
#ifdef Q_OS_LINUX
#ifndef __mobile__
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
if (!_runningUnitTests) {
if (getuid() == 0) {
_exitWithError(QString(
tr("You are running %1 as root. "
"You should not do this since it will cause other issues with %1."
"%1 will now exit.<br/><br/>"
"If you are having serial port issues on Ubuntu, execute the "
"following commands to fix most issues:<br/>"
"<pre>sudo usermod -a -G dialout $USER<br/>"
"sudo apt-get remove modemmanager</pre>")
.arg(qgcApp()->applicationName())));
return;
}
// Determine if we have the correct permissions to access USB serial devices
QFile permFile("/etc/group");
if (permFile.open(QIODevice::ReadOnly)) {
while (!permFile.atEnd()) {
QString line = permFile.readLine();
if (line.contains("dialout") && !line.contains(getenv("USER"))) {
permFile.close();
_exitWithError(
QString(tr("The current user does not have the correct "
"permissions to access serial devices. "
"You should also remove modemmanager since it also "
"interferes.<br/><br/>"
"If you are using Ubuntu, execute the following "
"commands to fix these issues:<br/>"
"<pre>sudo usermod -a -G dialout $USER<br/>"
"sudo apt-get remove modemmanager</pre>")));
return;
// Always set style to default, this way QT_QUICK_CONTROLS_STYLE environment
// variable doesn't cause random changes in ui
QQuickStyle::setStyle("Default");
}
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// Setup for network proxy support
QNetworkProxyFactory::setUseSystemConfiguration(true);
// Parse command line options
bool fClearSettingsOptions = false; // Clear stored settings
bool fClearCache = false; // Clear parameter/airframe caches
bool logging = false; // Turn on logging
QString loggingOptions;
CmdLineOpt_t rgCmdLineOptions[] = {
{"--clear-settings", &fClearSettingsOptions, nullptr},
{"--clear-cache", &fClearCache, nullptr},
{"--logging", &logging, &loggingOptions},
{"--fake-mobile", &_fakeMobile, nullptr},
{"--log-output", &_logOutput, nullptr},
// Add additional command line option flags here
};
ParseCmdLineOptions(argc, argv, rgCmdLineOptions,
sizeof(rgCmdLineOptions) / sizeof(rgCmdLineOptions[0]),
false);
// Set up timer for delayed missing fact display
_missingParamsDelayedDisplayTimer.setSingleShot(true);
_missingParamsDelayedDisplayTimer.setInterval(
_missingParamsDelayedDisplayTimerTimeout);
connect(&_missingParamsDelayedDisplayTimer, &QTimer::timeout, this,
&QGCApplication::_missingParamsDisplay);
// Set application information
QString applicationName;
if (_runningUnitTests) {
// We don't want unit tests to use the same QSettings space as the normal
// app. So we tweak the app name. Also we want to run unit tests with clean
// settings every time.
applicationName = QStringLiteral("%1_unittest").arg(QGC_APPLICATION_NAME);
} else {
// This gives daily builds their own separate settings space. Allowing you
// to use daily and stable builds side by side without daily screwing up
// your stable settings.
applicationName = QStringLiteral("%1 Daily").arg(QGC_APPLICATION_NAME);
applicationName = QGC_APPLICATION_NAME;
}
setApplicationName(applicationName);
setOrganizationName(QGC_ORG_NAME);
setOrganizationDomain(QGC_ORG_DOMAIN);
this->setApplicationVersion(QString(GIT_VERSION));
// Set settings format
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings;
qDebug() << "Settings location" << settings.fileName()
<< "Is writable?:" << settings.isWritable();
if (!settings.isWritable()) {
qWarning() << "Setings location is not writable";
}
// The setting will delete all settings on this boot
fClearSettingsOptions |= settings.contains(_deleteAllSettingsKey);
if (_runningUnitTests) {
// Unit tests run with clean settings
fClearSettingsOptions = true;
}
if (fClearSettingsOptions) {
// User requested settings to be cleared on command line
settings.clear();
// Clear parameter cache
QDir paramDir(ParameterManager::parameterCacheDir());
paramDir.removeRecursively();
paramDir.mkpath(paramDir.absolutePath());
} else {
// Determine if upgrade message for settings version bump is required. Check
// and clear must happen before toolbox is started since that will write
// some settings.
if (settings.contains(_settingsVersionKey)) {
if (settings.value(_settingsVersionKey).toInt() != QGC_SETTINGS_VERSION) {
_settingsUpgraded = true;
}
}
settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
if (fClearCache) {
QDir dir(ParameterManager::parameterCacheDir());
dir.removeRecursively();
QFile airframe(cachedAirframeMetaDataFile());
airframe.remove();
QFile parameter(cachedParameterMetaDataFile());
parameter.remove();
}
// Set up our logging filters
QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(
loggingOptions);
QBluetoothLocalDevice localDevice;
if (localDevice.isValid()) {
_bluetoothAvailable = true;
}
// Gstreamer debug settings
int gstDebugLevel = 0;
if (settings.contains(AppSettings::gstDebugLevelName)) {
gstDebugLevel = settings.value(AppSettings::gstDebugLevelName).toInt();
}
#if defined(QGC_GST_STREAMING)
// Initialize Video Receiver
GStreamer::initialize(argc, argv, gstDebugLevel);
// We need to set language as early as possible prior to loading on JSON
// files.
setLanguage();
_toolbox = new QGCToolbox(this);
_toolbox->setChildToolboxes();
_gpsRtkFactGroup = new GPSRTKFactGroup(this);
GPSManager *gpsManager = _toolbox->gpsManager();
if (gpsManager) {
connect(gpsManager, &GPSManager::onConnect, this,
&QGCApplication::_onGPSConnect);
connect(gpsManager, &GPSManager::onDisconnect, this,
&QGCApplication::_onGPSDisconnect);
connect(gpsManager, &GPSManager::surveyInStatus, this,
&QGCApplication::_gpsSurveyInStatus);
connect(gpsManager, &GPSManager::satelliteUpdate, this,
&QGCApplication::_gpsNumSatellites);
}
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
_checkForNewVersion();
}
void QGCApplication::_exitWithError(QString errorMessage) {
_error = true;
QQmlApplicationEngine *pEngine = new QQmlApplicationEngine(this);
pEngine->addImportPath("qrc:/qml");
pEngine->rootContext()->setContextProperty("errorMessage", errorMessage);
pEngine->load(QUrl(QStringLiteral("qrc:/qml/ExitWithErrorWindow.qml")));
// Exit main application when last window is closed
connect(this, &QGCApplication::lastWindowClosed, this, QGCApplication::quit);
}
void QGCApplication::setLanguage() {
_locale = QLocale::system();
qDebug() << "System reported locale:" << _locale << "; Name" << _locale.name()
<< "; Preffered (used in maps): "
<< (QLocale::system().uiLanguages().length() > 0
? QLocale::system().uiLanguages()[0]
: "None");
int langID = AppSettings::_languageID();
//-- See App.SettinsGroup.json for index
if (langID) {
switch (langID) {
case 1:
_locale = QLocale(QLocale::Bulgarian);
break;
case 2:
_locale = QLocale(QLocale::Chinese);
break;
case 3:
_locale = QLocale(QLocale::Dutch);
break;
case 4:
_locale = QLocale(QLocale::English);
break;
case 5:
_locale = QLocale(QLocale::Finnish);
break;
case 6:
_locale = QLocale(QLocale::French);
break;
case 7:
_locale = QLocale(QLocale::German);
break;
case 8:
_locale = QLocale(QLocale::Greek);
break;
case 9:
_locale = QLocale(QLocale::Hebrew);
break;
case 10:
_locale = QLocale(QLocale::Italian);
break;
case 11:
_locale = QLocale(QLocale::Japanese);
break;
case 12:
_locale = QLocale(QLocale::Korean);
break;
case 13:
_locale = QLocale(QLocale::Norwegian);
break;
case 14:
_locale = QLocale(QLocale::Polish);
break;
case 15:
_locale = QLocale(QLocale::Portuguese);
break;
case 16:
_locale = QLocale(QLocale::Russian);
break;
case 17:
_locale = QLocale(QLocale::Spanish);
break;
case 18:
_locale = QLocale(QLocale::Swedish);
break;
case 19:
_locale = QLocale(QLocale::Turkish);
break;
case 20:
_locale = QLocale(QLocale::Azerbaijani);
break;
}
//-- We have specific fonts for Korean
if (_locale == QLocale::Korean) {
qCDebug(LocalizationLog) << "Loading Korean fonts" << _locale.name();
if (QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Regular") < 0) {
qCWarning(LocalizationLog)
<< "Could not load /fonts/NanumGothic-Regular font";
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
if (QFontDatabase::addApplicationFont(":/fonts/NanumGothic-Bold") < 0) {
qCWarning(LocalizationLog)
<< "Could not load /fonts/NanumGothic-Bold font";
}
}
qCDebug(LocalizationLog) << "Loading localizations for" << _locale.name();
_app->removeTranslator(&_qgcTranslatorJSON);
_app->removeTranslator(&_qgcTranslatorSourceCode);
_app->removeTranslator(&_qgcTranslatorQtLibs);
if (_locale.name() != "en_US") {
QLocale::setDefault(_locale);
if (_qgcTranslatorQtLibs.load(
"qt_" + _locale.name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
_app->installTranslator(&_qgcTranslatorQtLibs);
} else {
qCWarning(LocalizationLog)
<< "Qt lib localization for" << _locale.name() << "is not present";
}
if (_qgcTranslatorSourceCode.load(_locale, QLatin1String("qgc_source_"), "",
":/i18n")) {
_app->installTranslator(&_qgcTranslatorSourceCode);
} else {
qCWarning(LocalizationLog)
<< "Error loading source localization for" << _locale.name();
}
if (_qgcTranslatorJSON.load(_locale, QLatin1String("qgc_json_"), "",
":/i18n")) {
_app->installTranslator(&_qgcTranslatorJSON);
} else {
qCWarning(LocalizationLog)
<< "Error loading json localization for" << _locale.name();
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
}
if (_qmlAppEngine)
_qmlAppEngine->retranslate();
emit languageChanged(_locale);
}
void QGCApplication::_shutdown() {
// Close out all Qml before we delete toolbox. This way we don't get all sorts
// of null reference complaints from Qml.
delete _qmlAppEngine;
delete _toolbox;
delete _gpsRtkFactGroup;
}
QGCApplication::~QGCApplication() {
// Place shutdown code in _shutdown
_app = nullptr;
}
void QGCApplication::_initCommon() {
static const char *kRefOnly = "Reference only";
static const char *kQGroundControl = "QGroundControl";
static const char *kQGCControllers = "QGroundControl.Controllers";
static const char *kQGCVehicle = "QGroundControl.Vehicle";
static const char *kQGCTemplates = "QGroundControl.Templates";
QSettings settings;
// Register our Qml objects
qmlRegisterType<QGCPalette>("QGroundControl.Palette", 1, 0, "QGCPalette");
qmlRegisterType<QGCMapPalette>("QGroundControl.Palette", 1, 0,
"QGCMapPalette");
qmlRegisterUncreatableType<Vehicle>(kQGCVehicle, 1, 0, "Vehicle", kRefOnly);
qmlRegisterUncreatableType<MissionManager>(kQGCVehicle, 1, 0,
"MissionManager", kRefOnly);
qmlRegisterUncreatableType<ParameterManager>(kQGCVehicle, 1, 0,
"ParameterManager", kRefOnly);
qmlRegisterUncreatableType<VehicleObjectAvoidance>(
kQGCVehicle, 1, 0, "VehicleObjectAvoidance", kRefOnly);
qmlRegisterUncreatableType<QGCCameraManager>(kQGCVehicle, 1, 0,
"QGCCameraManager", kRefOnly);
qmlRegisterUncreatableType<QGCCameraControl>(kQGCVehicle, 1, 0,
"QGCCameraControl", kRefOnly);
qmlRegisterUncreatableType<QGCVideoStreamInfo>(
kQGCVehicle, 1, 0, "QGCVideoStreamInfo", kRefOnly);
qmlRegisterUncreatableType<LinkInterface>(kQGCVehicle, 1, 0, "LinkInterface",
kRefOnly);
qmlRegisterUncreatableType<VehicleLinkManager>(
kQGCVehicle, 1, 0, "VehicleLinkManager", kRefOnly);
qmlRegisterUncreatableType<MissionController>(kQGCControllers, 1, 0,
"MissionController", kRefOnly);
qmlRegisterUncreatableType<GeoFenceController>(
kQGCControllers, 1, 0, "GeoFenceController", kRefOnly);
qmlRegisterUncreatableType<RallyPointController>(
kQGCControllers, 1, 0, "RallyPointController", kRefOnly);
qmlRegisterUncreatableType<MissionItem>(kQGroundControl, 1, 0, "MissionItem",
kRefOnly);
qmlRegisterUncreatableType<VisualMissionItem>(kQGroundControl, 1, 0,
"VisualMissionItem", kRefOnly);
qmlRegisterUncreatableType<FlightPathSegment>(kQGroundControl, 1, 0,
"FlightPathSegment", kRefOnly);
qmlRegisterUncreatableType<QmlObjectListModel>(
kQGroundControl, 1, 0, "QmlObjectListModel", kRefOnly);
qmlRegisterUncreatableType<MissionCommandTree>(
kQGroundControl, 1, 0, "MissionCommandTree", kRefOnly);
qmlRegisterUncreatableType<CameraCalc>(kQGroundControl, 1, 0, "CameraCalc",
kRefOnly);
qmlRegisterUncreatableType<LogReplayLink>(kQGroundControl, 1, 0,
"LogReplayLink", kRefOnly);
qmlRegisterUncreatableType<InstrumentValueData>(
kQGroundControl, 1, 0, "InstrumentValueData", kRefOnly);
qmlRegisterType<LogReplayLinkController>(kQGroundControl, 1, 0,
"LogReplayLinkController");
#if defined(QGC_ENABLE_MAVLINK_INSPECTOR)
qmlRegisterUncreatableType<MAVLinkChartController>(kQGroundControl, 1, 0,
"MAVLinkChart", kRefOnly);
#endif
#if defined(QGC_ENABLE_PAIRING)
qmlRegisterUncreatableType<PairingManager>(kQGroundControl, 1, 0,
"PairingManager", kRefOnly);
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
qmlRegisterUncreatableType<AutoPilotPlugin>(
"QGroundControl.AutoPilotPlugin", 1, 0, "AutoPilotPlugin", kRefOnly);
qmlRegisterUncreatableType<VehicleComponent>(
"QGroundControl.AutoPilotPlugin", 1, 0, "VehicleComponent", kRefOnly);
qmlRegisterUncreatableType<JoystickManager>(
"QGroundControl.JoystickManager", 1, 0, "JoystickManager", kRefOnly);
qmlRegisterUncreatableType<Joystick>("QGroundControl.JoystickManager", 1, 0,
"Joystick", kRefOnly);
qmlRegisterUncreatableType<QGCPositionManager>(
"QGroundControl.QGCPositionManager", 1, 0, "QGCPositionManager",
kRefOnly);
qmlRegisterUncreatableType<FactValueSliderListModel>(
"QGroundControl.FactControls", 1, 0, "FactValueSliderListModel",
kRefOnly);
qmlRegisterUncreatableType<QGCMapPolygon>("QGroundControl.FlightMap", 1, 0,
"QGCMapPolygon", kRefOnly);
qmlRegisterUncreatableType<QGCGeoBoundingCube>(
"QGroundControl.FlightMap", 1, 0, "QGCGeoBoundingCube", kRefOnly);
qmlRegisterUncreatableType<TrajectoryPoints>("QGroundControl.FlightMap", 1, 0,
"TrajectoryPoints", kRefOnly);
qmlRegisterUncreatableType<FactValueGrid>(kQGCTemplates, 1, 0,
"FactValueGrid", kRefOnly);
qmlRegisterType<HorizontalFactValueGrid>(kQGCTemplates, 1, 0,
"HorizontalFactValueGrid");
qmlRegisterType<QGCMapCircle>("QGroundControl.FlightMap", 1, 0,
"QGCMapCircle");
qmlRegisterType<ParameterEditorController>(kQGCControllers, 1, 0,
"ParameterEditorController");
qmlRegisterType<ESP8266ComponentController>(kQGCControllers, 1, 0,
"ESP8266ComponentController");
qmlRegisterType<ScreenToolsController>(kQGCControllers, 1, 0,
"ScreenToolsController");
qmlRegisterType<PlanMasterController>(kQGCControllers, 1, 0,
"PlanMasterController");
qmlRegisterType<QGCFileDialogController>(kQGCControllers, 1, 0,
"QGCFileDialogController");
qmlRegisterType<RCChannelMonitorController>(kQGCControllers, 1, 0,
"RCChannelMonitorController");
qmlRegisterType<JoystickConfigController>(kQGCControllers, 1, 0,
"JoystickConfigController");
qmlRegisterType<LogDownloadController>(kQGCControllers, 1, 0,
"LogDownloadController");
qmlRegisterType<SyslinkComponentController>(kQGCControllers, 1, 0,
"SyslinkComponentController");
qmlRegisterType<EditPositionDialogController>(kQGCControllers, 1, 0,
"EditPositionDialogController");
qmlRegisterType<RCToParamDialogController>(kQGCControllers, 1, 0,
"RCToParamDialogController");
qmlRegisterType<TerrainProfile>("QGroundControl.Controls", 1, 0,
"TerrainProfile");
qmlRegisterType<ToolStripAction>("QGroundControl.Controls", 1, 0,
"ToolStripAction");
qmlRegisterType<ToolStripActionList>("QGroundControl.Controls", 1, 0,
"ToolStripActionList");
#ifndef NO_SERIAL_LINK
qmlRegisterType<FirmwareUpgradeController>(kQGCControllers, 1, 0,
"FirmwareUpgradeController");
qmlRegisterUncreatableType<routing::LinearGenerator>(
"MeasurementComplexItem", 1, 0, "LinearGenerator", kRefOnly);
qmlRegisterType<AreaData>("MeasurementComplexItem", 1, 0, "AreaData");
qmlRegisterSingletonType<NemoInterface>("MeasurementComplexItem", 1, 0,
"NemoInterface", getNemoInterface);
qmlRegisterInterface<routing::GeneratorBase>("GeneratorBase");
qmlRegisterUncreatableType<routing::CircularGenerator>(
"MeasurementComplexItem", 1, 0, "CircularGenerator", kRefOnly);
qmlRegisterType<GeoTagController>(kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController>(kQGCControllers, 1, 0,
"MavlinkConsoleController");
#if defined(QGC_ENABLE_MAVLINK_INSPECTOR)
qmlRegisterType<MAVLinkInspectorController>(kQGCControllers, 1, 0,
"MAVLinkInspectorController");
// Register Qml Singletons
qmlRegisterSingletonType<QGroundControlQmlGlobal>(
"QGroundControl", 1, 0, "QGroundControl",
qgroundcontrolQmlGlobalSingletonFactory);
qmlRegisterSingletonType<ScreenToolsController>(
"QGroundControl.ScreenToolsController", 1, 0, "ScreenToolsController",
screenToolsControllerSingletonFactory);
qmlRegisterSingletonType<ShapeFileHelper>("QGroundControl.ShapeFileHelper", 1,
0, "ShapeFileHelper",
shapeFileHelperSingletonFactory);
qmlRegisterSingletonType<ShapeFileHelper>("MAVLink", 1, 0, "MAVLink",
mavlinkSingletonFactory);
// Although this should really be in _initForNormalAppBoot putting it here
// allowws us to create unit tests which pop up more easily
if (QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) {
qWarning() << "Could not load /fonts/opensans font";
}
if (QFontDatabase::addApplicationFont(":/fonts/opensans-demibold") < 0) {
qWarning() << "Could not load /fonts/opensans-demibold font";
}
bool QGCApplication::_initForNormalAppBoot() {
QSettings settings;
_qmlAppEngine = toolbox()->corePlugin()->createQmlApplicationEngine(this);
toolbox()->corePlugin()->createRootWindow(_qmlAppEngine);
// Image provider for PX4 Flow
QQuickImageProvider *pImgProvider =
dynamic_cast<QQuickImageProvider *>(qgcApp()->toolbox()->imageProvider());
_qmlAppEngine->addImageProvider(QStringLiteral("QGCImages"), pImgProvider);
QQuickWindow *rootWindow = (QQuickWindow *)qgcApp()->mainRootWindow();
if (rootWindow) {
rootWindow->scheduleRenderJob(
new FinishVideoInitialization(toolbox()->videoManager()),
QQuickWindow::BeforeSynchronizingStage);
}
// Safe to show popup error messages now that main window is created
UASMessageHandler *msgHandler = qgcApp()->toolbox()->uasMessageHandler();
if (msgHandler) {
msgHandler->showErrorsInToolbar();
}
dogmaphobic
committed
// Now that main window is up check for lost log files
connect(this, &QGCApplication::checkForLostLogFiles,
toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles);
emit checkForLostLogFiles();
dogmaphobic
committed
// Load known link configurations
toolbox()->linkManager()->loadLinkConfigurationList();
dogmaphobic
committed
// Probe for joysticks
toolbox()->joystickManager()->init();
if (_settingsUpgraded) {
showAppMessage(
QString(tr("The format for %1 saved settings has been modified. "
"Your saved settings have been reset to defaults."))
.arg(applicationName()));
}
// Connect links with flag AutoconnectLink
toolbox()->linkManager()->startAutoConnectedLinks();
if (getQGCMapEngine()->wasCacheReset()) {
showAppMessage(tr("The Offline Map Cache database has been upgraded. "
"Your old map cache sets have been reset."));
}
settings.sync();
return true;
bool QGCApplication::_initForUnitTests() { return true; }
void QGCApplication::deleteAllSettingsNextBoot(void) {
QSettings settings;
settings.setValue(_deleteAllSettingsKey, true);
void QGCApplication::clearDeleteAllSettingsNextBoot(void) {
QSettings settings;
settings.remove(_deleteAllSettingsKey);
}
/// @brief Returns the QGCApplication object singleton.
QGCApplication *qgcApp(void) { return QGCApplication::_app; }
void QGCApplication::informationMessageBoxOnMainThread(
const QString & /*title*/, const QString &msg) {
showAppMessage(msg);
void QGCApplication::warningMessageBoxOnMainThread(const QString & /*title*/,
const QString &msg) {
showAppMessage(msg);
void QGCApplication::criticalMessageBoxOnMainThread(const QString & /*title*/,
const QString &msg) {
showAppMessage(msg);
void QGCApplication::saveTelemetryLogOnMainThread(QString tempLogfile) {
// The vehicle is gone now and we are shutting down so we need to use a
// message box for errors to hold shutdown and show the error
if (_checkTelemetrySavePath(true /* useMessageBox */)) {
QString saveDirPath =
_toolbox->settingsManager()->appSettings()->telemetrySavePath();
QDir saveDir(saveDirPath);
QString nameFormat("%1%2.%3");
QString dtFormat("yyyy-MM-dd hh-mm-ss");
int tryIndex = 1;
QString saveFileName =
nameFormat.arg(QDateTime::currentDateTime().toString(dtFormat))
.arg(QStringLiteral(""))
.arg(toolbox()
->settingsManager()
->appSettings()
->telemetryFileExtension);
while (saveDir.exists(saveFileName)) {
saveFileName =
nameFormat.arg(QDateTime::currentDateTime().toString(dtFormat))
.arg(QStringLiteral(".%1").arg(tryIndex++))
.arg(toolbox()
->settingsManager()
->appSettings()
->telemetryFileExtension);
QString saveFilePath = saveDir.absoluteFilePath(saveFileName);
QFile tempFile(tempLogfile);
if (!tempFile.copy(saveFilePath)) {
QString error = tr("Unable to save telemetry log. Error copying "
"telemetry to '%1': '%2'.")
.arg(saveFilePath)
.arg(tempFile.errorString());
showAppMessage(error);
}
}
QFile::remove(tempLogfile);
void QGCApplication::checkTelemetrySavePathOnMainThread() {
// This is called with an active vehicle so don't pop message boxes which
// holds ui thread
_checkTelemetrySavePath(false /* useMessageBox */);
bool QGCApplication::_checkTelemetrySavePath(bool /*useMessageBox*/) {
QString saveDirPath =
_toolbox->settingsManager()->appSettings()->telemetrySavePath();
if (saveDirPath.isEmpty()) {
QString error = tr(
"Unable to save telemetry log. Application save directory is not set.");
showAppMessage(error);
return false;
}
QDir saveDir(saveDirPath);
if (!saveDir.exists()) {
QString error = tr("Unable to save telemetry log. Telemetry save directory "
"\"%1\" does not exist.")
.arg(saveDirPath);
showAppMessage(error);
return false;
}
dogmaphobic
committed
void QGCApplication::reportMissingParameter(int componentId,
const QString &name) {
QPair<int, QString> missingParam(componentId, name);
if (!_missingParams.contains(missingParam)) {
_missingParams.append(missingParam);
}
_missingParamsDelayedDisplayTimer.start();
}
/// Called when the delay timer fires to show the missing parameters warning
void QGCApplication::_missingParamsDisplay(void) {
if (_missingParams.count()) {
QString params;
for (QPair<int, QString> &missingParam : _missingParams) {
QString param = QStringLiteral("%1:%2")
.arg(missingParam.first)
.arg(missingParam.second);
if (params.isEmpty()) {
params += param;
} else {
params += QStringLiteral(", %1").arg(param);
}
showAppMessage(
tr("Parameters are missing from firmware. You may be running a version "
"of firmware which is not fully supported or your firmware has a "
"bug in it. Missing params: %1")
.arg(params));
}
QObject *QGCApplication::_rootQmlObject() {
if (_qmlAppEngine && _qmlAppEngine->rootObjects().size())
return _qmlAppEngine->rootObjects()[0];
return nullptr;
void QGCApplication::showCriticalVehicleMessage(const QString &message) {
// PreArm messages are handled by Vehicle and shown in Map
if (message.startsWith(QStringLiteral("PreArm")) ||
message.startsWith(QStringLiteral("preflight"), Qt::CaseInsensitive)) {
return;
}
QObject *rootQmlObject = _rootQmlObject();
if (rootQmlObject) {
QVariant varReturn;
QVariant varMessage = QVariant::fromValue(message);
QMetaObject::invokeMethod(_rootQmlObject(), "showCriticalVehicleMessage",
Q_RETURN_ARG(QVariant, varReturn),
Q_ARG(QVariant, varMessage));
} else if (runningUnitTests()) {
// Unit tests can run without UI
qDebug() << "QGCApplication::showCriticalVehicleMessage unittest"
<< message;
} else {
qWarning() << "Internal error";
}
}
void QGCApplication::showAppMessage(const QString &message,
const QString &title) {
QString dialogTitle = title.isEmpty() ? applicationName() : title;
QObject *rootQmlObject = _rootQmlObject();
if (rootQmlObject) {
QVariant varReturn;
QVariant varMessage = QVariant::fromValue(message);
QMetaObject::invokeMethod(_rootQmlObject(), "showMessageDialog",
Q_RETURN_ARG(QVariant, varReturn),
Q_ARG(QVariant, dialogTitle),
Q_ARG(QVariant, varMessage));
} else if (runningUnitTests()) {
// Unit tests can run without UI
qDebug() << "QGCApplication::showAppMessage unittest title:message"
<< dialogTitle << message;
} else {
// UI isn't ready yet
_delayedAppMessages.append(QPair<QString, QString>(dialogTitle, message));
QTimer::singleShot(200, this, &QGCApplication::_showDelayedAppMessages);
}
void QGCApplication::_showDelayedAppMessages(void) {
if (_rootQmlObject()) {
for (const QPair<QString, QString> &appMsg : _delayedAppMessages) {
showAppMessage(appMsg.second, appMsg.first);
_delayedAppMessages.clear();
} else {
QTimer::singleShot(200, this, &QGCApplication::_showDelayedAppMessages);
}
QQuickItem *QGCApplication::mainRootWindow() {
if (!_mainRootWindow) {
_mainRootWindow = reinterpret_cast<QQuickItem *>(_rootQmlObject());
}
return _mainRootWindow;
void QGCApplication::showSetupView() {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "showSetupTool");
}
void QGCApplication::qmlAttemptWindowClose() {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose");
}
bool QGCApplication::isInternetAvailable() {
if (_toolbox->settingsManager()
->appSettings()
->checkInternet()
->rawValue()
.toBool())
return getQGCMapEngine()->isInternetActive();
return true;
void QGCApplication::_checkForNewVersion() {
if (!_runningUnitTests) {
if (_parseVersionText(applicationVersion(), _majorVersion, _minorVersion,
_buildVersion)) {
QString versionCheckFile =
toolbox()->corePlugin()->stableVersionCheckFileUrl();
if (!versionCheckFile.isEmpty()) {