Newer
Older
/****************************************************************************
*
* (c) 2009-2016 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 <QStringListModel>
#include <QStyleFactory>
#ifdef QGC_ENABLE_BLUETOOTH
#include <QBluetoothLocalDevice>
#endif
#include "VideoStreaming.h"
#include "AutoPilotPlugin.h"
#include "CameraCalc.h"
#include "EditPositionDialogController.h"
#include "FactValueSliderListModel.h"
#include "FirmwareImage.h"
#include "FlightMapSettings.h"
#include "FollowMe.h"
#include "JoystickManager.h"
#include "LinkManager.h"
#include "LogDownloadController.h"
#include "MissionCommandTree.h"
#include "MultiVehicleManager.h"
#include "ParameterEditorController.h"
#include "ParameterManager.h"
#include "PlanMasterController.h"
#include "QGC.h"
#include "QGCApplication.h"
#include "QGCCameraManager.h"
#include "QGCCorePlugin.h"
#include "QGCFileDialogController.h"
#include "QGCFileDownload.h"
#include "QGCGeoBoundingCube.h"
#include "QGCLoggingCategory.h"
#include "QGCMapPalette.h"
#include "QGCMapPolygon.h"
#include "QGCPalette.h"
#include "QGCTemporaryFile.h"
#include "QGroundControlQmlGlobal.h"
#include "QmlObjectListModel.h"
#include "RCChannelMonitorController.h"
#include "ScreenToolsController.h"
#include "SimulatedPosition.h"
#include "SyslinkComponentController.h"
#include "UASMessageHandler.h"
#include "UDPLink.h"
#include "ValuesWidgetController.h"
#include "Vehicle.h"
#include "VehicleComponent.h"
#include "VideoManager.h"
#include "VideoReceiver.h"
#include "VideoSurface.h"
#include "ViewWidgetController.h"
#include "VisualMissionItem.h"
#include "Wima/Snake/NemoInterface.h"
#include "Wima/WimaController.h"
#include "Wima/WimaPlaner.h"
#include "FirmwareUpgradeController.h"
#include "GeoTagController.h"
#include "QGCMessageBox.h"
#include "QGCQFileDialog.h"
#ifdef QGC_RTLAB_ENABLED
#endif
#ifdef Q_OS_LINUX
#ifndef __mobile__
#include <sys/types.h>
QGCApplication *QGCApplication::_app = nullptr;
const char *QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot";
const char *QGCApplication::_settingsVersionKey = "SettingsVersion";
const char *QGCApplication::_darkStyleFile = ":/res/styles/style-dark.css";
const char *QGCApplication::_lightStyleFile = ":/res/styles/style-light.css";
// 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 *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;
QGCApplication::QGCApplication(int &argc, char *argv[], bool unitTesting)
: QGuiApplication(argc, argv), _qmlAppEngine(nullptr)
,
_runningUnitTests(unitTesting), _logOutput(false), _fakeMobile(false),
_settingsUpgraded(false), _majorVersion(0), _minorVersion(0),
_buildVersion(0), _currentVersionDownload(nullptr),
_gpsRtkFactGroup(nullptr), _toolbox(nullptr), _bluetoothAvailable(false) {
_app = this;
QLocale locale = QLocale::system();
//-- Some forced locales for testing
// QLocale locale = QLocale(QLocale::German);
// QLocale locale = QLocale(QLocale::French);
// QLocale locale = QLocale(QLocale::Chinese);
#if defined(__macos__)
locale = QLocale(locale.name());
qDebug() << "System reported locale:" << locale << locale.name();
//-- Our localization
if (_QGCTranslator.load(locale, "qgc_", "", ":/localization"))
_app->installTranslator(&_QGCTranslator);
// This prevents usage of QQuickWidget to fail since it doesn't support
// native widget siblings
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// Setup for network proxy support
QNetworkProxyFactory::setUseSystemConfiguration(true);
if (!_runningUnitTests) {
if (getuid() == 0) {
QMessageBox msgBox;
msgBox.setInformativeText(
tr("You are running %1 as root. "
"You should not do this since it will cause other issues with %1. "
"%1 will now exit. "
"If you are having serial port issues on Ubuntu, execute the "
"following commands to fix most issues:\n"
"sudo usermod -a -G dialout $USER\n"
"sudo apt-get remove modemmanager")
.arg(qgcApp()->applicationName()));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
_exit(0);
}
// 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"))) {
QMessageBox msgBox;
msgBox.setInformativeText(
"The current user does not have the correct permissions to "
"access serial devices. "
"You should also remove modemmanager since it also interferes. "
"If you are using Ubuntu, execute the following commands to fix "
"these issues:\n"
"sudo usermod -a -G dialout $USER\n"
"sudo apt-get remove modemmanager");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
break;
238
239
240
241
242
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
281
282
283
// 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
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.
setApplicationName(QString("%1_unittest").arg(QGC_APPLICATION_NAME));
} else {
setApplicationName(QGC_APPLICATION_NAME);
}
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;
}
} else if (settings.allKeys().count()) {
// Settings version key is missing and there are settings. This is an
// upgrade scenario.
settings.clear();
_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);
// Initialize Bluetooth
QBluetoothLocalDevice localDevice;
if (localDevice.isValid()) {
_bluetoothAvailable = true;
}
#if defined(__ios__) || defined(__android__)
// Initialize Video Streaming
initializeVideoStreaming(argc, argv, nullptr, nullptr);
QString savePath, gstDebugLevel;
if (settings.contains(AppSettings::savePathName)) {
savePath = settings.value(AppSettings::savePathName).toString();
}
if (savePath.isEmpty()) {
savePath = "/tmp";
}
savePath = savePath + "/Logs/gst";
if (!QDir(savePath).exists()) {
QDir().mkpath(savePath);
}
if (settings.contains(AppSettings::gstDebugLevelName)) {
gstDebugLevel =
"*:" + settings.value(AppSettings::gstDebugLevelName).toString();
}
// Initialize Video Streaming
initializeVideoStreaming(argc, argv, savePath.toUtf8().data(),
gstDebugLevel.toUtf8().data());
_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);
}
void QGCApplication::_shutdown(void) {
// This code is specifically not in the destructor since the application
// object may not be available in the destructor. This cause problems for
// deleting object like settings which are in the toolbox which may have qml
// references. By moving them here and having main.cc call this prior to
// deleting the app object we make sure app object is still around while these
// things are shutting down.
MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) {
delete mainWindow;
}
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
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
shutdownVideoStreaming();
delete _toolbox;
}
QGCApplication::~QGCApplication() {
// Place shutdown code in _shutdown
_app = nullptr;
}
void QGCApplication::_initCommon(void) {
static const char *kRefOnly = "Reference only";
static const char *kQGCControllers = "QGroundControl.Controllers";
static const char *kQGCVehicle = "QGroundControl.Vehicle";
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<MissionItem>(kQGCVehicle, 1, 0, "MissionItem",
kRefOnly);
qmlRegisterUncreatableType<MissionManager>(kQGCVehicle, 1, 0,
"MissionManager", kRefOnly);
qmlRegisterUncreatableType<ParameterManager>(kQGCVehicle, 1, 0,
"ParameterManager", 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<MissionController>(kQGCControllers, 1, 0,
"MissionController", kRefOnly);
qmlRegisterUncreatableType<GeoFenceController>(
kQGCControllers, 1, 0, "GeoFenceController", kRefOnly);
qmlRegisterUncreatableType<RallyPointController>(
kQGCControllers, 1, 0, "RallyPointController", kRefOnly);
qmlRegisterUncreatableType<VisualMissionItem>(kQGCControllers, 1, 0,
"VisualMissionItem", kRefOnly);
qmlRegisterUncreatableType<CoordinateVector>("QGroundControl", 1, 0,
"CoordinateVector", kRefOnly);
qmlRegisterUncreatableType<QmlObjectListModel>(
"QGroundControl", 1, 0, "QmlObjectListModel", kRefOnly);
qmlRegisterUncreatableType<MissionCommandTree>(
"QGroundControl", 1, 0, "MissionCommandTree", kRefOnly);
qmlRegisterUncreatableType<CameraCalc>("QGroundControl", 1, 0, "CameraCalc",
kRefOnly);
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);
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<ValuesWidgetController>(kQGCControllers, 1, 0,
"ValuesWidgetController");
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<ViewWidgetController>(kQGCControllers, 1, 0,
"ViewWidgetController");
qmlRegisterType<CustomCommandWidgetController>(
kQGCControllers, 1, 0, "CustomCommandWidgetController");
#ifndef NO_SERIAL_LINK
qmlRegisterType<FirmwareUpgradeController>(kQGCControllers, 1, 0,
"FirmwareUpgradeController");
qmlRegisterType<GeoTagController>(kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController>(kQGCControllers, 1, 0,
"MavlinkConsoleController");
// Wima
qmlRegisterType<WimaController>("Wima", 1, 0, "WimaController");
qmlRegisterType<WimaPlaner>("Wima", 1, 0, "WimaPlaner");
qmlRegisterType<NemoInterface>("Wima", 1, 0, "NemoInterface");
// 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);
bool QGCApplication::_initForNormalAppBoot(void) {
QSettings settings;
dogmaphobic
committed
// Exit main application when last window is closed
connect(this, &QGCApplication::lastWindowClosed, this, QGCApplication::quit);
_qmlAppEngine = toolbox()->corePlugin()->createRootWindow(this);
// Start the user interface
MainWindow *mainWindow = MainWindow::_create();
Q_CHECK_PTR(mainWindow);
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) {
showMessage(
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()) {
showMessage(tr("The Offline Map Cache database has been upgraded. "
"Your old map cache sets have been reset."));
}
settings.sync();
return true;
bool QGCApplication::_initForUnitTests(void) { 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) {
Q_UNUSED(title);
showMessage(msg);
void QGCApplication::warningMessageBoxOnMainThread(const QString &title,
const QString &msg) {
Q_UNUSED(title)
showMessage(msg);
QGCMessageBox::warning(title, msg);
void QGCApplication::criticalMessageBoxOnMainThread(const QString &title,
const QString &msg) {
Q_UNUSED(title)
showMessage(msg);
QGCMessageBox::critical(title, 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);
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
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("")
.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());
QGCMessageBox::warning(tr("Telemetry Save Error"), error);
}
QFile::remove(tempLogfile);
void QGCApplication::checkTelemetrySavePathOnMainThread(void) {
// 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 errorTitle = tr("Telemetry save error");
QString saveDirPath =
_toolbox->settingsManager()->appSettings()->telemetrySavePath();
if (saveDirPath.isEmpty()) {
QString error = tr(
"Unable to save telemetry log. Application save directory is not set.");
if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error);
} else {
Q_UNUSED(useMessageBox);
showMessage(error);
#endif
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);
if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error);
} else {
#endif
return false;
}
void QGCApplication::_loadCurrentStyleSheet(void) {
bool success = true;
QString styles;
// The dark style sheet is the master. Any other selected style sheet just
// overrides the colors of the master sheet.
QFile masterStyleSheet(_darkStyleFile);
if (masterStyleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
styles = masterStyleSheet.readAll();
} else {
qDebug() << "Unable to load master dark style sheet";
success = false;
}
if (success && !_toolbox->settingsManager()
->appSettings()
->indoorPalette()
->rawValue()
.toBool()) {
// Load the slave light stylesheet.
QFile styleSheet(_lightStyleFile);
if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
styles += styleSheet.readAll();
qWarning() << "Unable to load slave light sheet:";
success = false;
dogmaphobic
committed
dogmaphobic
committed
if (!success) {
// Fall back to plastique if we can't load our own
setStyle("plastique");
}
void QGCApplication::reportMissingParameter(int componentId,
const QString &name) {
_missingParams += QString("%1:%2").arg(componentId).arg(name);
_missingParamsDelayedDisplayTimer.start();
/// Called when the delay timer fires to show the missing parameters warning
void QGCApplication::_missingParamsDisplay(void) {
if (_missingParams.count()) {
QString params;
foreach (const QString &name, _missingParams) {
if (params.isEmpty()) {
params += name;
} else {
params += QString(", %1").arg(name);
}
_missingParams.clear();
showMessage(tr("Parameters are missing from firmware. You may be running a "
"version of firmware QGC does not work correctly with 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;
MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) {
return mainWindow->rootQmlObject();
} else if (runningUnitTests()) {
// Unit test can run without a main window
return nullptr;
} else {
qWarning() << "Why is MainWindow missing?";
return nullptr;
}
void QGCApplication::showMessage(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(), "showMessage",
Q_RETURN_ARG(QVariant, varReturn),
Q_ARG(QVariant, varMessage));
} else if (runningUnitTests()) {
// Unit test can run without a main window which will lead to no root qml
// object. Use QGCMessageBox instead
QGCMessageBox::information("Unit Test", message);
} else {
qWarning() << "Internal error";
}
void QGCApplication::showSetupView(void) {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "showSetupView");
}
void QGCApplication::qmlAttemptWindowClose(void) {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose");
}
bool QGCApplication::isInternetAvailable() {
return getQGCMapEngine()->isInternetActive();
void QGCApplication::_checkForNewVersion(void) {
if (!_runningUnitTests) {
if (_parseVersionText(applicationVersion(), _majorVersion, _minorVersion,
_buildVersion)) {
QString versionCheckFile =
toolbox()->corePlugin()->stableVersionCheckFileUrl();
if (!versionCheckFile.isEmpty()) {
_currentVersionDownload = new QGCFileDownload(this);
connect(_currentVersionDownload, &QGCFileDownload::downloadFinished,
this, &QGCApplication::_currentVersionDownloadFinished);
connect(_currentVersionDownload, &QGCFileDownload::error, this,
&QGCApplication::_currentVersionDownloadError);
_currentVersionDownload->download(versionCheckFile);
}
void QGCApplication::_currentVersionDownloadFinished(QString remoteFile,
QString localFile) {
Q_UNUSED(remoteFile);
QFile versionFile(localFile);
if (versionFile.open(QIODevice::ReadOnly)) {
QTextStream textStream(&versionFile);
QString version = textStream.readLine();
qDebug() << version;
int majorVersion, minorVersion, buildVersion;
if (_parseVersionText(version, majorVersion, minorVersion, buildVersion)) {
if (_majorVersion < majorVersion ||
(_majorVersion == majorVersion && _minorVersion < minorVersion) ||
(_majorVersion == majorVersion && _minorVersion == minorVersion &&
_buildVersion < buildVersion)) {
QGCMessageBox::information(
tr("New Version Available"),
tr("There is a newer version of %1 available. You can download it "
"from %2.")
.arg(applicationName())
.arg(toolbox()->corePlugin()->stableDownloadLocation()));
}
_currentVersionDownload->deleteLater();
void QGCApplication::_currentVersionDownloadError(QString errorMsg) {
Q_UNUSED(errorMsg);
_currentVersionDownload->deleteLater();
bool QGCApplication::_parseVersionText(const QString &versionString,
int &majorVersion, int &minorVersion,
int &buildVersion) {
QRegularExpression regExp("v(\\d+)\\.(\\d+)\\.(\\d+)");
QRegularExpressionMatch match = regExp.match(versionString);
if (match.hasMatch() && match.lastCapturedIndex() == 3) {
majorVersion = match.captured(1).toInt();
minorVersion = match.captured(2).toInt();
buildVersion = match.captured(3).toInt();
return true;
}
void QGCApplication::_onGPSConnect() {
_gpsRtkFactGroup->connected()->setRawValue(true);
void QGCApplication::_onGPSDisconnect() {
_gpsRtkFactGroup->connected()->setRawValue(false);
void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM,
double latitude, double longitude,
float altitude, bool valid,
bool active) {
_gpsRtkFactGroup->currentDuration()->setRawValue(duration);
_gpsRtkFactGroup->currentAccuracy()->setRawValue(accuracyMM / 1000.0);
_gpsRtkFactGroup->currentLatitude()->setRawValue(latitude);
_gpsRtkFactGroup->currentLongitude()->setRawValue(longitude);
_gpsRtkFactGroup->currentAltitude()->setRawValue(altitude);
_gpsRtkFactGroup->valid()->setRawValue(valid);
_gpsRtkFactGroup->active()->setRawValue(active);
void QGCApplication::_gpsNumSatellites(int numSatellites) {
_gpsRtkFactGroup->numSatellites()->setRawValue(numSatellites);
QString QGCApplication::cachedParameterMetaDataFile(void) {
QSettings settings;
QDir parameterDir = QFileInfo(settings.fileName()).dir();
return parameterDir.filePath(QStringLiteral("ParameterFactMetaData.xml"));
QString QGCApplication::cachedAirframeMetaDataFile(void) {
QSettings settings;
QDir airframeDir = QFileInfo(settings.fileName()).dir();
return airframeDir.filePath(QStringLiteral("PX4AirframeFactMetaData.xml"));