QGCApplication.cc 27.4 KB
Newer Older
1
 /*=====================================================================
2

Don Gagne's avatar
Don Gagne committed
3
 QGroundControl Open Source Ground Control Station
4

Don Gagne's avatar
Don Gagne committed
5
 (c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
6

Don Gagne's avatar
Don Gagne committed
7
 This file is part of the QGROUNDCONTROL project
8

Don Gagne's avatar
Don Gagne committed
9 10 11 12
 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
13

Don Gagne's avatar
Don Gagne committed
14 15 16 17
 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
18

Don Gagne's avatar
Don Gagne committed
19 20
 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
21

Don Gagne's avatar
Don Gagne committed
22
 ======================================================================*/
pixhawk's avatar
pixhawk committed
23 24 25

/**
 * @file
Don Gagne's avatar
Don Gagne committed
26
 *   @brief Implementation of class QGCApplication
pixhawk's avatar
pixhawk committed
27 28 29 30 31 32 33 34 35 36 37 38
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QFile>
#include <QFlags>
#include <QPixmap>
#include <QDesktopWidget>
#include <QPainter>
#include <QStyleFactory>
#include <QAction>
39
#include <QStringListModel>
pixhawk's avatar
pixhawk committed
40

dogmaphobic's avatar
dogmaphobic committed
41 42 43 44
#ifdef QGC_ENABLE_BLUETOOTH
#include <QBluetoothLocalDevice>
#endif

45 46
#include <QDebug>

47
#include "VideoStreaming.h"
Gus Grubba's avatar
Gus Grubba committed
48

49
#include "QGC.h"
Don Gagne's avatar
Don Gagne committed
50
#include "QGCApplication.h"
pixhawk's avatar
pixhawk committed
51
#include "GAudioOutput.h"
52
#include "CmdLineOptParser.h"
53 54
#include "UDPLink.h"
#include "LinkManager.h"
55
#include "HomePositionManager.h"
56
#include "UASMessageHandler.h"
57
#include "AutoPilotPluginManager.h"
58
#include "QGCTemporaryFile.h"
59
#include "QGCPalette.h"
Don Gagne's avatar
Don Gagne committed
60
#include "QGCMapPalette.h"
61
#include "QGCLoggingCategory.h"
Don Gagne's avatar
Don Gagne committed
62 63
#include "ViewWidgetController.h"
#include "ParameterEditorController.h"
Don Gagne's avatar
Don Gagne committed
64
#include "CustomCommandWidgetController.h"
Don Gagne's avatar
Don Gagne committed
65 66
#include "PX4AdvancedFlightModesController.h"
#include "PX4SimpleFlightModesController.h"
Don Gagne's avatar
Don Gagne committed
67
#include "APMFlightModesComponentController.h"
Don Gagne's avatar
Don Gagne committed
68 69
#include "AirframeComponentController.h"
#include "SensorsComponentController.h"
Don Gagne's avatar
Don Gagne committed
70
#include "APMSensorsComponentController.h"
71
#include "PowerComponentController.h"
Don Gagne's avatar
Don Gagne committed
72
#include "RadioComponentController.h"
dogmaphobic's avatar
dogmaphobic committed
73
#include "ESP8266ComponentController.h"
Don Gagne's avatar
Don Gagne committed
74
#include "ScreenToolsController.h"
Don Gagne's avatar
Don Gagne committed
75
#include "QGCMobileFileDialogController.h"
Don Gagne's avatar
Don Gagne committed
76
#include "RCChannelMonitorController.h"
77 78
#include "AutoPilotPlugin.h"
#include "VehicleComponent.h"
Don Gagne's avatar
Don Gagne committed
79
#include "FirmwarePluginManager.h"
80
#include "MultiVehicleManager.h"
81
#include "APM/ArduCopterFirmwarePlugin.h"
82 83
#include "APM/ArduPlaneFirmwarePlugin.h"
#include "APM/ArduRoverFirmwarePlugin.h"
84
#include "APM/APMAirframeComponentController.h"
Don Gagne's avatar
Don Gagne committed
85
#include "PX4/PX4FirmwarePlugin.h"
86
#include "Vehicle.h"
87
#include "MavlinkQmlSingleton.h"
88
#include "JoystickManager.h"
89
#include "QmlObjectListModel.h"
Don Gagne's avatar
Don Gagne committed
90
#include "MissionManager.h"
91 92
#include "QGroundControlQmlGlobal.h"
#include "HomePositionManager.h"
93
#include "FlightMapSettings.h"
94 95
#include "QGCQGeoCoordinate.h"
#include "CoordinateVector.h"
96
#include "MainToolBarController.h"
97
#include "MissionController.h"
Don Gagne's avatar
Don Gagne committed
98
#include "MissionCommands.h"
99 100 101
#include "FlightDisplayViewController.h"
#include "VideoSurface.h"
#include "VideoReceiver.h"
dogmaphobic's avatar
dogmaphobic committed
102
#include "LogDownloadController.h"
103
#include "PX4AirframeLoader.h"
104
#include "ValuesWidgetController.h"
105
#include "AppMessages.h"
Jimmy Johnson's avatar
Jimmy Johnson committed
106 107 108
#include "SimulatedPosition.h"
#include "PositionManager.h"
#include "FollowMe.h"
109 110 111 112 113 114

#ifndef __ios__
    #include "SerialLink.h"
#endif

#ifndef __mobile__
115 116
    #include "QGCFileDialog.h"
    #include "QGCMessageBox.h"
117 118
    #include "FirmwareUpgradeController.h"
    #include "JoystickConfigController.h"
Don Gagne's avatar
Don Gagne committed
119
    #include "MainWindow.h"
120
#endif
121

122
#ifdef QGC_RTLAB_ENABLED
123
    #include "OpalLink.h"
124
#endif
125

Don Gagne's avatar
Don Gagne committed
126 127 128 129 130 131
#ifdef Q_OS_LINUX
#ifndef __mobile__
#include <unistd.h>
#include <sys/types.h>
#endif
#endif
132 133

QGCApplication* QGCApplication::_app = NULL;
pixhawk's avatar
pixhawk committed
134

Don Gagne's avatar
Don Gagne committed
135 136 137 138
const char* QGCApplication::parameterFileExtension =    "params";
const char* QGCApplication::missionFileExtension =      "mission";
const char* QGCApplication::telemetryFileExtension =     "tlog";

139 140 141 142 143
const char* QGCApplication::_deleteAllSettingsKey           = "DeleteAllSettingsNextBoot";
const char* QGCApplication::_settingsVersionKey             = "SettingsVersion";
const char* QGCApplication::_promptFlightDataSave           = "PromptFLightDataSave";
const char* QGCApplication::_promptFlightDataSaveNotArmed   = "PromptFLightDataSaveNotArmed";
const char* QGCApplication::_styleKey                       = "StyleIsDark";
144 145 146
const char* QGCApplication::_lastKnownHomePositionLatKey    = "LastKnownHomePositionLat";
const char* QGCApplication::_lastKnownHomePositionLonKey    = "LastKnownHomePositionLon";
const char* QGCApplication::_lastKnownHomePositionAltKey    = "LastKnownHomePositionAlt";
Don Gagne's avatar
Don Gagne committed
147

dogmaphobic's avatar
dogmaphobic committed
148 149
const char* QGCApplication::_darkStyleFile          = ":/res/styles/style-dark.css";
const char* QGCApplication::_lightStyleFile         = ":/res/styles/style-light.css";
150

151
// Qml Singleton factories
152

Don Gagne's avatar
Don Gagne committed
153
static QObject* screenToolsControllerSingletonFactory(QQmlEngine*, QJSEngine*)
154
{
Don Gagne's avatar
Don Gagne committed
155 156
    ScreenToolsController* screenToolsController = new ScreenToolsController;
    return screenToolsController;
157 158
}

159 160 161 162 163
static QObject* mavlinkQmlSingletonFactory(QQmlEngine*, QJSEngine*)
{
    return new MavlinkQmlSingleton;
}

164 165
static QObject* qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine*, QJSEngine*)
{
166
    // We create this object as a QGCTool even though it isn't in the toolbox
167 168 169 170
    QGroundControlQmlGlobal* qmlGlobal = new QGroundControlQmlGlobal(qgcApp());
    qmlGlobal->setToolbox(qgcApp()->toolbox());

    return qmlGlobal;
171 172
}

pixhawk's avatar
pixhawk committed
173 174 175 176 177 178 179 180 181 182
/**
 * @brief Constructor for the main application.
 *
 * This constructor initializes and starts the whole application. It takes standard
 * command-line parameters
 *
 * @param argc The number of command-line parameters
 * @param argv The string array of parameters
 **/

183
QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
Don Gagne's avatar
Don Gagne committed
184 185 186 187
#ifdef __mobile__
    : QGuiApplication(argc, argv)
    , _qmlAppEngine(NULL)
#else
188
    : QApplication(argc, argv)
Don Gagne's avatar
Don Gagne committed
189
#endif
190
    , _runningUnitTests(unitTesting)
dogmaphobic's avatar
dogmaphobic committed
191 192 193
#if defined (__mobile__)
    , _styleIsDark(false)
#else
194
    , _styleIsDark(true)
dogmaphobic's avatar
dogmaphobic committed
195
#endif
dogmaphobic's avatar
dogmaphobic committed
196
    , _fakeMobile(false)
197 198 199
#ifdef QT_DEBUG
    , _testHighDPI(false)
#endif
200
    , _toolbox(NULL)
dogmaphobic's avatar
dogmaphobic committed
201
    , _bluetoothAvailable(false)
202
    , _lastKnownHomePosition(37.803784, -122.462276, 0.0)
pixhawk's avatar
pixhawk committed
203
{
204 205
    Q_ASSERT(_app == NULL);
    _app = this;
206

207
    // This prevents usage of QQuickWidget to fail since it doesn't support native widget siblings
dogmaphobic's avatar
dogmaphobic committed
208
#ifndef __android__
209
    setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
dogmaphobic's avatar
dogmaphobic committed
210
#endif
dogmaphobic's avatar
dogmaphobic committed
211

212 213
#ifdef Q_OS_LINUX
#ifndef __mobile__
214 215 216 217 218 219 220 221 222 223 224 225 226 227
    if (!_runningUnitTests) {
        if (getuid() == 0) {
            QMessageBox msgBox;
            msgBox.setInformativeText("You are runnning QGroundControl as root. "
                                      "You should not do this since it will cause other issues with QGroundControl. "
                                      "QGroundControl 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");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
            _exit(0);
        }
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        // 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;
                }
246
            }
247
            permFile.close();
248 249 250 251 252
        }
    }
#endif
#endif

253
    // Parse command line options
dogmaphobic's avatar
dogmaphobic committed
254

255
    bool fClearSettingsOptions = false; // Clear stored settings
256 257
    bool logging = false;               // Turn on logging
    QString loggingOptions;
dogmaphobic's avatar
dogmaphobic committed
258

259
    CmdLineOpt_t rgCmdLineOptions[] = {
260 261
        { "--clear-settings",   &fClearSettingsOptions, NULL },
        { "--logging",          &logging,               &loggingOptions },
dogmaphobic's avatar
dogmaphobic committed
262
        { "--fake-mobile",      &_fakeMobile,           NULL },
263
#ifdef QT_DEBUG
264
        { "--test-high-dpi",    &_testHighDPI,          NULL },
265
#endif
266 267
        // Add additional command line option flags here
    };
dogmaphobic's avatar
dogmaphobic committed
268

269
    ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false);
270

271
    // Set up timer for delayed missing fact display
Don Gagne's avatar
Don Gagne committed
272 273 274
    _missingParamsDelayedDisplayTimer.setSingleShot(true);
    _missingParamsDelayedDisplayTimer.setInterval(_missingParamsDelayedDisplayTimerTimeout);
    connect(&_missingParamsDelayedDisplayTimer, &QTimer::timeout, this, &QGCApplication::_missingParamsDisplay);
dogmaphobic's avatar
dogmaphobic committed
275

Don Gagne's avatar
Don Gagne committed
276
    // Set application information
277 278 279 280 281 282 283 284 285
    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);
286

287
    QString versionString(GIT_TAG);
Daniel Agar's avatar
Daniel Agar committed
288 289 290 291 292
    // stable versions are on tags (v1.2.3)
    // development versions are full git describe versions (v1.2.3-18-g879e8b3)
    if (versionString.length() > 8) {
        versionString.append(" (Development)");
    }
Don Gagne's avatar
Don Gagne committed
293
    this->setApplicationVersion(versionString);
294

295 296
    // Set settings format
    QSettings::setDefaultFormat(QSettings::IniFormat);
297
    QSettings settings;
298
    qDebug() << "Settings location" << settings.fileName() << "Is writable?:" << settings.isWritable();
Don Gagne's avatar
Don Gagne committed
299

300
#ifdef UNITTEST_BUILD
Don Gagne's avatar
Don Gagne committed
301 302 303
    if (!settings.isWritable()) {
        qWarning() << "Setings location is not writable";
    }
304
#endif
305
    // The setting will delete all settings on this boot
Don Gagne's avatar
Don Gagne committed
306
    fClearSettingsOptions |= settings.contains(_deleteAllSettingsKey);
307

Don Gagne's avatar
Don Gagne committed
308
    if (_runningUnitTests) {
309
        // Unit tests run with clean settings
Don Gagne's avatar
Don Gagne committed
310 311
        fClearSettingsOptions = true;
    }
312

313 314
    if (fClearSettingsOptions) {
        // User requested settings to be cleared on command line
315

316
        settings.clear();
317
        settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
318

319
        // Clear parameter cache
320 321 322
        QDir paramDir(ParameterLoader::parameterCacheDir());
        paramDir.removeRecursively();
        paramDir.mkpath(paramDir.absolutePath());
323
    }
Gus Grubba's avatar
Gus Grubba committed
324

325 326 327
    // Set up our logging filters
    QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(loggingOptions);

328 329 330
    _lastKnownHomePosition.setLatitude(settings.value(_lastKnownHomePositionLatKey, 37.803784).toDouble());
    _lastKnownHomePosition.setLongitude(settings.value(_lastKnownHomePositionLonKey, -122.462276).toDouble());
    _lastKnownHomePosition.setAltitude(settings.value(_lastKnownHomePositionAltKey, 0.0).toDouble());
Don Gagne's avatar
Don Gagne committed
331

dogmaphobic's avatar
dogmaphobic committed
332 333 334 335 336 337 338 339 340
    // Initialize Bluetooth
#ifdef QGC_ENABLE_BLUETOOTH
    QBluetoothLocalDevice localDevice;
    if (localDevice.isValid())
    {
        _bluetoothAvailable = true;
    }
#endif

341 342
    // Initialize Video Streaming
    initializeVideoStreaming(argc, argv);
343 344

    _toolbox = new QGCToolbox(this);
345 346
}

Don Gagne's avatar
Don Gagne committed
347 348
QGCApplication::~QGCApplication()
{
Don Gagne's avatar
Don Gagne committed
349
#ifndef __mobile__
Don Gagne's avatar
Don Gagne committed
350 351 352 353
    MainWindow* mainWindow = MainWindow::instance();
    if (mainWindow) {
        delete mainWindow;
    }
Don Gagne's avatar
Don Gagne committed
354
#endif
355
    shutdownVideoStreaming();
356
    delete _toolbox;
Don Gagne's avatar
Don Gagne committed
357 358
}

359
void QGCApplication::_initCommon(void)
360 361
{
    QSettings settings;
362

Don Gagne's avatar
Don Gagne committed
363
    // Register our Qml objects
dogmaphobic's avatar
dogmaphobic committed
364

Don Gagne's avatar
Don Gagne committed
365 366
    qmlRegisterType<QGCPalette>     ("QGroundControl.Palette", 1, 0, "QGCPalette");
    qmlRegisterType<QGCMapPalette>  ("QGroundControl.Palette", 1, 0, "QGCMapPalette");
dogmaphobic's avatar
dogmaphobic committed
367

Don Gagne's avatar
Don Gagne committed
368 369 370 371 372 373 374
    qmlRegisterUncreatableType<CoordinateVector>    ("QGroundControl",                  1, 0, "CoordinateVector",       "Reference only");
    qmlRegisterUncreatableType<MissionCommands>     ("QGroundControl",                  1, 0, "MissionCommands",        "Reference only");
    qmlRegisterUncreatableType<QGCQGeoCoordinate>   ("QGroundControl",                  1, 0, "QGCQGeoCoordinate",      "Reference only");
    qmlRegisterUncreatableType<QmlObjectListModel>  ("QGroundControl",                  1, 0, "QmlObjectListModel",     "Reference only");
    qmlRegisterUncreatableType<VideoReceiver>       ("QGroundControl",                  1, 0, "VideoReceiver",          "Reference only");
    qmlRegisterUncreatableType<VideoSurface>        ("QGroundControl",                  1, 0, "VideoSurface",           "Reference only");

375 376 377 378 379 380 381
    qmlRegisterUncreatableType<AutoPilotPlugin>     ("QGroundControl.AutoPilotPlugin",  1, 0, "AutoPilotPlugin",        "Reference only");
    qmlRegisterUncreatableType<VehicleComponent>    ("QGroundControl.AutoPilotPlugin",  1, 0, "VehicleComponent",       "Reference only");
    qmlRegisterUncreatableType<Vehicle>             ("QGroundControl.Vehicle",          1, 0, "Vehicle",                "Reference only");
    qmlRegisterUncreatableType<MissionItem>         ("QGroundControl.Vehicle",          1, 0, "MissionItem",            "Reference only");
    qmlRegisterUncreatableType<MissionManager>      ("QGroundControl.Vehicle",          1, 0, "MissionManager",         "Reference only");
    qmlRegisterUncreatableType<JoystickManager>     ("QGroundControl.JoystickManager",  1, 0, "JoystickManager",        "Reference only");
    qmlRegisterUncreatableType<Joystick>            ("QGroundControl.JoystickManager",  1, 0, "Joystick",               "Reference only");
Jimmy Johnson's avatar
Jimmy Johnson committed
382
    qmlRegisterUncreatableType<QGCPositionManager>  ("QGroundControl.QGCPositionManager",  1, 0, "QGCPositionManager",  "Reference only");
383

dogmaphobic's avatar
dogmaphobic committed
384
    qmlRegisterType<ParameterEditorController>          ("QGroundControl.Controllers", 1, 0, "ParameterEditorController");
Don Gagne's avatar
Don Gagne committed
385
    qmlRegisterType<APMFlightModesComponentController>  ("QGroundControl.Controllers", 1, 0, "APMFlightModesComponentController");
Don Gagne's avatar
Don Gagne committed
386 387
    qmlRegisterType<PX4AdvancedFlightModesController>   ("QGroundControl.Controllers", 1, 0, "PX4AdvancedFlightModesController");
    qmlRegisterType<PX4SimpleFlightModesController>     ("QGroundControl.Controllers", 1, 0, "PX4SimpleFlightModesController");
388
    qmlRegisterType<APMAirframeComponentController>     ("QGroundControl.Controllers", 1, 0, "APMAirframeComponentController");
Don Gagne's avatar
Don Gagne committed
389
    qmlRegisterType<AirframeComponentController>        ("QGroundControl.Controllers", 1, 0, "AirframeComponentController");
Don Gagne's avatar
Don Gagne committed
390
    qmlRegisterType<APMSensorsComponentController>      ("QGroundControl.Controllers", 1, 0, "APMSensorsComponentController");
Don Gagne's avatar
Don Gagne committed
391 392 393
    qmlRegisterType<SensorsComponentController>         ("QGroundControl.Controllers", 1, 0, "SensorsComponentController");
    qmlRegisterType<PowerComponentController>           ("QGroundControl.Controllers", 1, 0, "PowerComponentController");
    qmlRegisterType<RadioComponentController>           ("QGroundControl.Controllers", 1, 0, "RadioComponentController");
dogmaphobic's avatar
dogmaphobic committed
394
    qmlRegisterType<ESP8266ComponentController>         ("QGroundControl.Controllers", 1, 0, "ESP8266ComponentController");
Don Gagne's avatar
Don Gagne committed
395 396 397 398
    qmlRegisterType<ScreenToolsController>              ("QGroundControl.Controllers", 1, 0, "ScreenToolsController");
    qmlRegisterType<MainToolBarController>              ("QGroundControl.Controllers", 1, 0, "MainToolBarController");
    qmlRegisterType<MissionController>                  ("QGroundControl.Controllers", 1, 0, "MissionController");
    qmlRegisterType<FlightDisplayViewController>        ("QGroundControl.Controllers", 1, 0, "FlightDisplayViewController");
399
    qmlRegisterType<ValuesWidgetController>             ("QGroundControl.Controllers", 1, 0, "ValuesWidgetController");
Don Gagne's avatar
Don Gagne committed
400
    qmlRegisterType<QGCMobileFileDialogController>      ("QGroundControl.Controllers", 1, 0, "QGCMobileFileDialogController");
Don Gagne's avatar
Don Gagne committed
401
    qmlRegisterType<RCChannelMonitorController>         ("QGroundControl.Controllers", 1, 0, "RCChannelMonitorController");
402

Don Gagne's avatar
Don Gagne committed
403
#ifndef __mobile__
404 405
    qmlRegisterType<ViewWidgetController>           ("QGroundControl.Controllers", 1, 0, "ViewWidgetController");
    qmlRegisterType<CustomCommandWidgetController>  ("QGroundControl.Controllers", 1, 0, "CustomCommandWidgetController");
406
    qmlRegisterType<FirmwareUpgradeController>      ("QGroundControl.Controllers", 1, 0, "FirmwareUpgradeController");
407
    qmlRegisterType<JoystickConfigController>       ("QGroundControl.Controllers", 1, 0, "JoystickConfigController");
dogmaphobic's avatar
dogmaphobic committed
408
    qmlRegisterType<LogDownloadController>          ("QGroundControl.Controllers", 1, 0, "LogDownloadController");
Don Gagne's avatar
Don Gagne committed
409
#endif
dogmaphobic's avatar
dogmaphobic committed
410

411
    // Register Qml Singletons
412 413 414
    qmlRegisterSingletonType<QGroundControlQmlGlobal>   ("QGroundControl",                          1, 0, "QGroundControl",         qgroundcontrolQmlGlobalSingletonFactory);
    qmlRegisterSingletonType<ScreenToolsController>     ("QGroundControl.ScreenToolsController",    1, 0, "ScreenToolsController",  screenToolsControllerSingletonFactory);
    qmlRegisterSingletonType<MavlinkQmlSingleton>       ("QGroundControl.Mavlink",                  1, 0, "Mavlink",                mavlinkQmlSingletonFactory);
415 416 417 418 419
}

bool QGCApplication::_initForNormalAppBoot(void)
{
    QSettings settings;
420

421 422
    _styleIsDark = settings.value(_styleKey, _styleIsDark).toBool();
    _loadCurrentStyle();
Lorenz Meier's avatar
Lorenz Meier committed
423

424
    // Exit main application when last window is closed
425
    connect(this, &QGCApplication::lastWindowClosed, this, QGCApplication::quit);
426

Don Gagne's avatar
Don Gagne committed
427 428 429 430
#ifdef __mobile__
    _qmlAppEngine = new QQmlApplicationEngine(this);
    _qmlAppEngine->addImportPath("qrc:/qml");
    _qmlAppEngine->rootContext()->setContextProperty("joystickManager", toolbox()->joystickManager());
431
    _qmlAppEngine->rootContext()->setContextProperty("debugMessageModel", AppMessages::getModel());
Don Gagne's avatar
Don Gagne committed
432 433
    _qmlAppEngine->load(QUrl(QStringLiteral("qrc:/qml/MainWindowNative.qml")));
#else
pixhawk's avatar
pixhawk committed
434
    // Start the user interface
Lorenz Meier's avatar
Lorenz Meier committed
435
    MainWindow* mainWindow = MainWindow::_create();
Don Gagne's avatar
Don Gagne committed
436
    Q_CHECK_PTR(mainWindow);
437

438
    // Now that main window is up check for lost log files
439
    connect(this, &QGCApplication::checkForLostLogFiles, toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles);
440
    emit checkForLostLogFiles();
Don Gagne's avatar
Don Gagne committed
441
#endif
442 443

    // Load known link configurations
444
    toolbox()->linkManager()->loadLinkConfigurationList();
445

Don Gagne's avatar
Don Gagne committed
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    // Show user an upgrade message if the settings version has been bumped up
    bool settingsUpgraded = false;
    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.
        settingsUpgraded = true;
    } else {
        settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
    }

    if (settingsUpgraded) {
        settings.clear();
        settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
        showMessage("The format for QGroundControl saved settings has been modified. "
                    "Your saved settings have been reset to defaults.");
    }

    settings.sync();

468
    return true;
pixhawk's avatar
pixhawk committed
469 470
}

471
bool QGCApplication::_initForUnitTests(void)
pixhawk's avatar
pixhawk committed
472
{
473
    return true;
pixhawk's avatar
pixhawk committed
474 475
}

Don Gagne's avatar
Don Gagne committed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
void QGCApplication::deleteAllSettingsNextBoot(void)
{
    QSettings settings;
    settings.setValue(_deleteAllSettingsKey, true);
}

void QGCApplication::clearDeleteAllSettingsNextBoot(void)
{
    QSettings settings;
    settings.remove(_deleteAllSettingsKey);
}

bool QGCApplication::promptFlightDataSave(void)
{
    QSettings settings;
491

Don Gagne's avatar
Don Gagne committed
492 493 494
    return settings.value(_promptFlightDataSave, true).toBool();
}

495 496 497 498 499 500 501
bool QGCApplication::promptFlightDataSaveNotArmed(void)
{
    QSettings settings;

    return settings.value(_promptFlightDataSaveNotArmed, false).toBool();
}

Don Gagne's avatar
Don Gagne committed
502 503 504 505 506 507
void QGCApplication::setPromptFlightDataSave(bool promptForSave)
{
    QSettings settings;
    settings.setValue(_promptFlightDataSave, promptForSave);
}

508 509 510 511 512 513
void QGCApplication::setPromptFlightDataSaveNotArmed(bool promptForSave)
{
    QSettings settings;
    settings.setValue(_promptFlightDataSaveNotArmed, promptForSave);
}

Don Gagne's avatar
Don Gagne committed
514 515 516
/// @brief Returns the QGCApplication object singleton.
QGCApplication* qgcApp(void)
{
517 518 519 520
    Q_ASSERT(QGCApplication::_app);
    return QGCApplication::_app;
}

521 522
void QGCApplication::informationMessageBoxOnMainThread(const QString& title, const QString& msg)
{
523 524
    Q_UNUSED(title);
    showMessage(msg);
525 526 527 528
}

void QGCApplication::warningMessageBoxOnMainThread(const QString& title, const QString& msg)
{
529 530 531 532
#ifdef __mobile__
    Q_UNUSED(title)
    showMessage(msg);
#else
533
    QGCMessageBox::warning(title, msg);
534
#endif
535 536 537 538
}

void QGCApplication::criticalMessageBoxOnMainThread(const QString& title, const QString& msg)
{
539 540 541 542
#ifdef __mobile__
    Q_UNUSED(title)
    showMessage(msg);
#else
543
    QGCMessageBox::critical(title, msg);
544
#endif
545 546
}

547
#ifndef __mobile__
548 549
void QGCApplication::saveTempFlightDataLogOnMainThread(QString tempLogfile)
{
550 551 552 553 554 555
    bool saveError;
    do{
        saveError = false;
        QString saveFilename = QGCFileDialog::getSaveFileName(
            MainWindow::instance(),
            tr("Save Flight Data Log"),
556
            QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
557 558
            tr("Flight Data Log Files (*.mavlink)"),
            "mavlink");
dogmaphobic's avatar
dogmaphobic committed
559

560 561 562
        if (!saveFilename.isEmpty()) {
            // if file exsits already, try to remove it first to overwrite it
            if(QFile::exists(saveFilename) && !QFile::remove(saveFilename)){
563
                // if the file cannot be removed, prompt user and ask new path
564
                saveError = true;
565
                QGCMessageBox::warning("File Error","Could not overwrite existing file.\nPlease provide a different file name to save to.");
566 567 568
            } else if(!QFile::copy(tempLogfile, saveFilename)) {
                // if file could not be copied, prompt user and ask new path
                saveError = true;
569
                QGCMessageBox::warning("File Error","Could not create file.\nPlease provide a different file name to save to.");
570 571 572
            }
        }
    } while(saveError); // if the file could not be overwritten, ask for new file
573 574
    QFile::remove(tempLogfile);
}
575
#endif
576 577 578 579

void QGCApplication::setStyle(bool styleIsDark)
{
    QSettings settings;
580

581 582 583 584 585 586 587 588
    settings.setValue(_styleKey, styleIsDark);
    _styleIsDark = styleIsDark;
    _loadCurrentStyle();
    emit styleChanged(_styleIsDark);
}

void QGCApplication::_loadCurrentStyle(void)
{
Don Gagne's avatar
Don Gagne committed
589
#ifndef __mobile__
590 591
    bool success = true;
    QString styles;
592

593 594 595 596 597 598 599 600 601
    // 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;
    }
602

603 604 605 606 607 608
    if (success && !_styleIsDark) {
        // Load the slave light stylesheet.
        QFile styleSheet(_lightStyleFile);
        if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
            styles += styleSheet.readAll();
        } else {
609
            qWarning() << "Unable to load slave light sheet:";
610 611 612
            success = false;
        }
    }
dogmaphobic's avatar
dogmaphobic committed
613

614
    setStyleSheet(styles);
615

616 617 618 619
    if (!success) {
        // Fall back to plastique if we can't load our own
        setStyle("plastique");
    }
Don Gagne's avatar
Don Gagne committed
620
#endif
621

622
    QGCPalette::setGlobalTheme(_styleIsDark ? QGCPalette::Dark : QGCPalette::Light);
623
}
Don Gagne's avatar
Don Gagne committed
624

Don Gagne's avatar
Don Gagne committed
625
void QGCApplication::reportMissingParameter(int componentId, const QString& name)
626
{
Don Gagne's avatar
Don Gagne committed
627 628
    _missingParams += QString("%1:%2").arg(componentId).arg(name);
    _missingParamsDelayedDisplayTimer.start();
629
}
630

Don Gagne's avatar
Don Gagne committed
631 632
/// Called when the delay timer fires to show the missing parameters warning
void QGCApplication::_missingParamsDisplay(void)
633
{
Don Gagne's avatar
Don Gagne committed
634
    Q_ASSERT(_missingParams.count());
dogmaphobic's avatar
dogmaphobic committed
635

Don Gagne's avatar
Don Gagne committed
636
    QString params;
637
    foreach (const QString &name, _missingParams) {
Don Gagne's avatar
Don Gagne committed
638 639
        if (params.isEmpty()) {
            params += name;
640
        } else {
Don Gagne's avatar
Don Gagne committed
641
            params += QString(", %1").arg(name);
642 643
        }
    }
Don Gagne's avatar
Don Gagne committed
644
    _missingParams.clear();
dogmaphobic's avatar
dogmaphobic committed
645

646
    showMessage(QString("Parameters missing from firmware: %1. You may be running an older version of firmware QGC does not work correctly with or your firmware has a bug in it.").arg(params));
647 648
}

Don Gagne's avatar
Don Gagne committed
649 650 651 652 653
QObject* QGCApplication::_rootQmlObject(void)
{
#ifdef __mobile__
    return _qmlAppEngine->rootObjects()[0];
#else
654 655 656 657 658 659 660 661 662 663
    MainWindow * mainWindow = MainWindow::instance();
    if (mainWindow) {
        return mainWindow->rootQmlObject();
    } else if (runningUnitTests()){
        // Unit test can run without a main window
        return NULL;
    } else {
        qWarning() << "Why is MainWindow missing?";
        return NULL;
    }
Don Gagne's avatar
Don Gagne committed
664 665 666 667
#endif
}


668
void QGCApplication::showMessage(const QString& message)
Don Gagne's avatar
Don Gagne committed
669
{
Don Gagne's avatar
Don Gagne committed
670 671 672 673 674
    // Special case hack for ArduPilot prearm messages. These show up in the center of the map, so no need for popup.
    if (message.contains("PreArm:")) {
        return;
    }

675 676 677 678 679
    QObject* rootQmlObject = _rootQmlObject();

    if (rootQmlObject) {
        QVariant varReturn;
        QVariant varMessage = QVariant::fromValue(message);
Don Gagne's avatar
Don Gagne committed
680

681 682 683 684 685 686 687 688 689
        QMetaObject::invokeMethod(_rootQmlObject(), "showMessage", Q_RETURN_ARG(QVariant, varReturn), Q_ARG(QVariant, varMessage));
#ifndef __mobile__
    } 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);
#endif
    } else {
        qWarning() << "Internal error";
    }
Don Gagne's avatar
Don Gagne committed
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
}

void QGCApplication::showFlyView(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showFlyView");
}

void QGCApplication::showPlanView(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showPlanView");
}

void QGCApplication::showSetupView(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showSetupView");
}

707
void QGCApplication::qmlAttemptWindowClose(void)
Don Gagne's avatar
Don Gagne committed
708
{
709
    QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose");
Don Gagne's avatar
Don Gagne committed
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
}


void QGCApplication::_showSetupFirmware(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showSetupFirmware");
}

void QGCApplication::_showSetupParameters(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showSetupParameters");
}

void QGCApplication::_showSetupSummary(void)
{
    QMetaObject::invokeMethod(_rootQmlObject(), "showSetupSummary");
}

void QGCApplication::_showSetupVehicleComponent(VehicleComponent* vehicleComponent)
{
    QVariant varReturn;
    QVariant varComponent = QVariant::fromValue(vehicleComponent);

    QMetaObject::invokeMethod(_rootQmlObject(), "showSetupVehicleComponent", Q_RETURN_ARG(QVariant, varReturn), Q_ARG(QVariant, varComponent));
Don Gagne's avatar
Don Gagne committed
734
}
Don Gagne's avatar
Don Gagne committed
735

736
void QGCApplication::setLastKnownHomePosition(QGeoCoordinate& lastKnownHomePosition)
Don Gagne's avatar
Don Gagne committed
737 738 739
{
    QSettings settings;

740 741 742 743
    settings.setValue(_lastKnownHomePositionLatKey, lastKnownHomePosition.latitude());
    settings.setValue(_lastKnownHomePositionLonKey, lastKnownHomePosition.longitude());
    settings.setValue(_lastKnownHomePositionAltKey, lastKnownHomePosition.altitude());
    _lastKnownHomePosition = lastKnownHomePosition;
Don Gagne's avatar
Don Gagne committed
744
}