Commit dedb0c51 authored by Valentin Platzgummer's avatar Valentin Platzgummer

nemo interface moved to wima planer

parent 529f7da8
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -273,7 +273,6 @@ FlightMap {
MapItemView {
id: tileView
property bool _enable: wimaController.enableWimaController.value
&& wimaController.enableSnake.value
property bool valid: wimaController.snakeTileCenterPoints.length
=== wimaController.nemoProgress.length
model: _enable ? wimaController.snakeTiles : 0
......
......@@ -46,7 +46,6 @@ Item {
// Use Settings to store menu appearance through different sessions.
Settings {
property alias snakeHeaderChecker: snakeHeader.checked
property alias missionHeaderChecker: missionHeader.checked
property alias navigateHeaderChecker: navigateHeader.checked
property alias vehicleHeaderChecker: vehicleHeader.checked
......@@ -98,7 +97,6 @@ Item {
property var enableWimaFact: wimaController.enableWimaController
property bool enableWimaBoolean: enableWimaFact.value
property var enableSnakeFact: wimaController.enableSnake
onAccept: {
if (enableWimaBoolean) {
......@@ -108,7 +106,6 @@ Item {
} else {
enableWimaFact.value = true
enableWimaMouseArea.enabled = false
enableSnakeCheckBox.checkedState = false;
timer.stop()
}
}
......@@ -176,56 +173,6 @@ Item {
id: mainColumn
spacing: ScreenTools.defaultFontPixelHeight * 0.3
SectionHeader{
id: snakeHeader
text: qsTr("Snake Settings")
}
Column {
visible: snakeHeader.checked
spacing: ScreenTools.defaultFontPixelHeight * 0.5
FactCheckBox {
id: enableSnakeCheckBox
text: wimaController.enableSnake.value ?
qsTr("Disable Snake")
: qsTr("Enable Snake")
fact: wimaController.enableSnake
}
// Spacer
Item {
height: 1
}
// Snake status and settings column.
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
visible: wimaController.enableSnake.value
// Snake connection status.
QGCLabel {
property int index: wimaController.nemoStatus
property string statusString: wimaController.nemoStatusString
text: "Status: " + statusString
Layout.fillWidth: true
}
// Snake calculation status.
QGCLabel {
property bool _calcInProgress: wimaController.snakeCalcInProgress
text: _calcInProgress === true ?
qsTr("Calculation: In Progress")
: qsTr("Calculation: Idle")
Layout.fillWidth: true
}
}
}
SectionHeader{
id: missionHeader
......
......@@ -143,7 +143,7 @@ Rectangle {
model: len
delegate: QGCRadioButton {
checked: index === variantRepeater.variant
text: variantRepeater.names[index]
text: variantRepeater.names[index] ? variantRepeater.names[index]: ""
onCheckedChanged: {
if (checked){
......
......@@ -7,7 +7,6 @@
*
****************************************************************************/
/**
* @file
* @brief Implementation of class QGCApplication
......@@ -16,15 +15,15 @@
*
*/
#include <QAction>
#include <QDesktopWidget>
#include <QFile>
#include <QFlags>
#include <QPixmap>
#include <QDesktopWidget>
#include <QPainter>
#include <QStyleFactory>
#include <QAction>
#include <QStringListModel>
#include <QPixmap>
#include <QRegularExpression>
#include <QStringListModel>
#include <QStyleFactory>
#ifdef QGC_ENABLE_BLUETOOTH
#include <QBluetoothLocalDevice>
......@@ -34,78 +33,79 @@
#include "VideoStreaming.h"
#include "QGC.h"
#include "QGCApplication.h"
#include "AppMessages.h"
#include "AudioOutput.h"
#include "AutoPilotPlugin.h"
#include "CameraCalc.h"
#include "CmdLineOptParser.h"
#include "UDPLink.h"
#include "LinkManager.h"
#include "UASMessageHandler.h"
#include "QGCTemporaryFile.h"
#include "QGCPalette.h"
#include "QGCMapPalette.h"
#include "QGCLoggingCategory.h"
#include "ViewWidgetController.h"
#include "ParameterEditorController.h"
#include "CoordinateVector.h"
#include "CustomCommandWidgetController.h"
#include "ESP8266ComponentController.h"
#include "ScreenToolsController.h"
#include "QGCFileDialogController.h"
#include "RCChannelMonitorController.h"
#include "SyslinkComponentController.h"
#include "AutoPilotPlugin.h"
#include "VehicleComponent.h"
#include "EditPositionDialogController.h"
#include "FactValueSliderListModel.h"
#include "FirmwareImage.h"
#include "FirmwarePluginManager.h"
#include "MultiVehicleManager.h"
#include "Vehicle.h"
#include "FlightMapSettings.h"
#include "FollowMe.h"
#include "JoystickConfigController.h"
#include "JoystickManager.h"
#include "QmlObjectListModel.h"
#include "QGCGeoBoundingCube.h"
#include "LinkManager.h"
#include "LogDownloadController.h"
#include "MissionCommandTree.h"
#include "MissionManager.h"
#include "QGroundControlQmlGlobal.h"
#include "FlightMapSettings.h"
#include "CoordinateVector.h"
#include "MultiVehicleManager.h"
#include "ParameterEditorController.h"
#include "ParameterManager.h"
#include "PlanMasterController.h"
#include "Wima/WimaController.h"
#include "Wima/WimaBridge.h"
#include "Wima/WimaPlaner.h"
#include "VideoManager.h"
#include "VideoSurface.h"
#include "VideoReceiver.h"
#include "LogDownloadController.h"
#include "ValuesWidgetController.h"
#include "AppMessages.h"
#include "SimulatedPosition.h"
#include "PositionManager.h"
#include "FollowMe.h"
#include "MissionCommandTree.h"
#include "QGCMapPolygon.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 "QGCMapCircle.h"
#include "ParameterManager.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 "SettingsManager.h"
#include "QGCCorePlugin.h"
#include "QGCCameraManager.h"
#include "CameraCalc.h"
#include "VisualMissionItem.h"
#include "EditPositionDialogController.h"
#include "FactValueSliderListModel.h"
#include "ShapeFileHelper.h"
#include "QGCFileDownload.h"
#include "FirmwareImage.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/WimaBridge.h"
#include "Wima/WimaController.h"
#include "Wima/WimaPlaner.h"
#ifndef NO_SERIAL_LINK
#include "SerialLink.h"
#endif
#ifndef __mobile__
#include "QGCQFileDialog.h"
#include "QGCMessageBox.h"
#include "FirmwareUpgradeController.h"
#include "MainWindow.h"
#include "GPS/GPSManager.h"
#include "GeoTagController.h"
#include "MainWindow.h"
#include "MavlinkConsoleController.h"
#include "GPS/GPSManager.h"
#include "QGCMessageBox.h"
#include "QGCQFileDialog.h"
#endif
#ifdef QGC_RTLAB_ENABLED
......@@ -114,82 +114,74 @@
#ifdef Q_OS_LINUX
#ifndef __mobile__
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#endif
#include "QGCMapEngine.h"
QGCApplication* QGCApplication::_app = nullptr;
QGCApplication *QGCApplication::_app = nullptr;
const char* QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot";
const char* QGCApplication::_settingsVersionKey = "SettingsVersion";
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";
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];
// Qml Singleton factories
static QObject* screenToolsControllerSingletonFactory(QQmlEngine*, QJSEngine*)
{
ScreenToolsController* screenToolsController = new ScreenToolsController;
static QObject *screenToolsControllerSingletonFactory(QQmlEngine *,
QJSEngine *) {
ScreenToolsController *screenToolsController = new ScreenToolsController;
return screenToolsController;
}
static QObject* qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine*, QJSEngine*)
{
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());
QGroundControlQmlGlobal *qmlGlobal =
new QGroundControlQmlGlobal(qgcApp(), qgcApp()->toolbox());
qmlGlobal->setToolbox(qgcApp()->toolbox());
return qmlGlobal;
}
static QObject* shapeFileHelperSingletonFactory(QQmlEngine*, QJSEngine*)
{
static QObject *shapeFileHelperSingletonFactory(QQmlEngine *, QJSEngine *) {
return new ShapeFileHelper;
}
QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
QGCApplication::QGCApplication(int &argc, char *argv[], bool unitTesting)
#ifdef __mobile__
: QGuiApplication (argc, argv)
, _qmlAppEngine (nullptr)
: QGuiApplication(argc, argv), _qmlAppEngine(nullptr)
#else
: QApplication (argc, argv)
: QApplication(argc, argv)
#endif
, _runningUnitTests (unitTesting)
, _logOutput (false)
, _fakeMobile (false)
, _settingsUpgraded (false)
, _majorVersion (0)
, _minorVersion (0)
, _buildVersion (0)
, _currentVersionDownload (nullptr)
, _gpsRtkFactGroup (nullptr)
, _toolbox (nullptr)
, _bluetoothAvailable (false)
{
,
_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__)
// QLocale locale = QLocale(QLocale::German);
// QLocale locale = QLocale(QLocale::French);
// QLocale locale = QLocale(QLocale::Chinese);
#if defined(__macos__)
locale = QLocale(locale.name());
#endif
qDebug() << "System reported locale:" << locale << locale.name();
//-- Our localization
if(_QGCTranslator.load(locale, "qgc_", "", ":/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
// This prevents usage of QQuickWidget to fail since it doesn't support
// native widget siblings
#ifndef __android__
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#endif
......@@ -202,12 +194,15 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
if (!_runningUnitTests) {
if (getuid() == 0) {
QMessageBox msgBox;
msgBox.setInformativeText(tr("You are running %1 as root. "
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"
"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()));
"sudo apt-get remove modemmanager")
.arg(qgcApp()->applicationName()));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
......@@ -216,14 +211,17 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
// Determine if we have the correct permissions to access USB serial devices
QFile permFile("/etc/group");
if(permFile.open(QIODevice::ReadOnly)) {
while(!permFile.atEnd()) {
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. "
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"
"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);
......@@ -246,25 +244,30 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
QString loggingOptions;
CmdLineOpt_t rgCmdLineOptions[] = {
{ "--clear-settings", &fClearSettingsOptions, nullptr },
{ "--clear-cache", &fClearCache, nullptr },
{ "--logging", &logging, &loggingOptions },
{ "--fake-mobile", &_fakeMobile, nullptr },
{ "--log-output", &_logOutput, nullptr },
{"--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);
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);
_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.
// 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);
......@@ -277,7 +280,8 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
// Set settings format
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings;
qDebug() << "Settings location" << settings.fileName() << "Is writable?:" << settings.isWritable();
qDebug() << "Settings location" << settings.fileName()
<< "Is writable?:" << settings.isWritable();
#ifdef UNITTEST_BUILD
if (!settings.isWritable()) {
......@@ -301,15 +305,17 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
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.
// 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) {
settings.clear();
_settingsUpgraded = true;
}
} else if (settings.allKeys().count()) {
// Settings version key is missing and there are settings. This is an upgrade scenario.
// Settings version key is missing and there are settings. This is an
// upgrade scenario.
settings.clear();
_settingsUpgraded = true;
}
......@@ -326,13 +332,13 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
}
// Set up our logging filters
QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(loggingOptions);
QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(
loggingOptions);
// Initialize Bluetooth
#ifdef QGC_ENABLE_BLUETOOTHsubPolylines
QBluetoothLocalDevice localDevice;
if (localDevice.isValid())
{
if (localDevice.isValid()) {
_bluetoothAvailable = true;
}
#endif
......@@ -346,7 +352,7 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
if (settings.contains(AppSettings::savePathName)) {
savePath = settings.value(AppSettings::savePathName).toString();
}
if(savePath.isEmpty()) {
if (savePath.isEmpty()) {
savePath = "/tmp";
}
savePath = savePath + "/Logs/gst";
......@@ -354,10 +360,12 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
QDir().mkpath(savePath);
}
if (settings.contains(AppSettings::gstDebugLevelName)) {
gstDebugLevel = "*:" + settings.value(AppSettings::gstDebugLevelName).toString();
gstDebugLevel =
"*:" + settings.value(AppSettings::gstDebugLevelName).toString();
}
// Initialize Video Streaming
initializeVideoStreaming(argc, argv, savePath.toUtf8().data(), gstDebugLevel.toUtf8().data());
initializeVideoStreaming(argc, argv, savePath.toUtf8().data(),
gstDebugLevel.toUtf8().data());
#endif
_toolbox = new QGCToolbox(this);
......@@ -367,24 +375,29 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
_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);
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);
}
#endif /* __mobile__ */
_checkForNewVersion();
}
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.
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.
#ifndef __mobile__
MainWindow* mainWindow = MainWindow::instance();
MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) {
delete mainWindow;
}
......@@ -393,92 +406,136 @@ void QGCApplication::_shutdown(void)
delete _toolbox;
}
QGCApplication::~QGCApplication()
{
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";
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<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");
#ifndef __mobile__
qmlRegisterType<ViewWidgetController> (kQGCControllers, 1, 0, "ViewWidgetController");
qmlRegisterType<CustomCommandWidgetController> (kQGCControllers, 1, 0, "CustomCommandWidgetController");
qmlRegisterType<ViewWidgetController>(kQGCControllers, 1, 0,
"ViewWidgetController");
qmlRegisterType<CustomCommandWidgetController>(
kQGCControllers, 1, 0, "CustomCommandWidgetController");
#ifndef NO_SERIAL_LINK
qmlRegisterType<FirmwareUpgradeController> (kQGCControllers, 1, 0, "FirmwareUpgradeController");
qmlRegisterType<FirmwareUpgradeController>(kQGCControllers, 1, 0,
"FirmwareUpgradeController");
#endif
qmlRegisterType<GeoTagController> (kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController> (kQGCControllers, 1, 0, "MavlinkConsoleController");
qmlRegisterType<GeoTagController>(kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController>(kQGCControllers, 1, 0,
"MavlinkConsoleController");
#endif
// Wima
qmlRegisterType<WimaController> ("Wima", 1, 0, "WimaController");
qmlRegisterType<WimaPlaner> ("Wima", 1, 0, "WimaPlaner");
qmlRegisterType<WimaBridge> ("Wima", 1, 0, "WimaBridge");
qmlRegisterType<WimaController>("Wima", 1, 0, "WimaController");
qmlRegisterType<WimaPlaner>("Wima", 1, 0, "WimaPlaner");
qmlRegisterType<WimaBridge>("Wima", 1, 0, "WimaBridge");
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)
{
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;
_loadCurrentStyleSheet();
......@@ -490,12 +547,13 @@ bool QGCApplication::_initForNormalAppBoot(void)
_qmlAppEngine = toolbox()->corePlugin()->createRootWindow(this);
#else
// Start the user interface
MainWindow* mainWindow = MainWindow::_create();
MainWindow *mainWindow = MainWindow::_create();
Q_CHECK_PTR(mainWindow);
#endif
// Now that main window is up check for lost log files
connect(this, &QGCApplication::checkForLostLogFiles, toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles);
connect(this, &QGCApplication::checkForLostLogFiles,
toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles);
emit checkForLostLogFiles();
// Load known link configurations
......@@ -505,8 +563,10 @@ bool QGCApplication::_initForNormalAppBoot(void)
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()));
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
......@@ -521,37 +581,29 @@ bool QGCApplication::_initForNormalAppBoot(void)
return true;
}
bool QGCApplication::_initForUnitTests(void)
{
return true;
}
bool QGCApplication::_initForUnitTests(void) { return true; }
void QGCApplication::deleteAllSettingsNextBoot(void)
{
void QGCApplication::deleteAllSettingsNextBoot(void) {
QSettings settings;
settings.setValue(_deleteAllSettingsKey, true);
}
void QGCApplication::clearDeleteAllSettingsNextBoot(void)
{
void QGCApplication::clearDeleteAllSettingsNextBoot(void) {
QSettings settings;
settings.remove(_deleteAllSettingsKey);
}
/// @brief Returns the QGCApplication object singleton.
QGCApplication* qgcApp(void)
{
return QGCApplication::_app;
}
QGCApplication *qgcApp(void) { return QGCApplication::_app; }
void QGCApplication::informationMessageBoxOnMainThread(const QString& title, const QString& msg)
{
void QGCApplication::informationMessageBoxOnMainThread(const QString &title,
const QString &msg) {
Q_UNUSED(title);
showMessage(msg);
}
void QGCApplication::warningMessageBoxOnMainThread(const QString& title, const QString& msg)
{
void QGCApplication::warningMessageBoxOnMainThread(const QString &title,
const QString &msg) {
#ifdef __mobile__
Q_UNUSED(title)
showMessage(msg);
......@@ -560,8 +612,8 @@ void QGCApplication::warningMessageBoxOnMainThread(const QString& title, const Q
#endif
}
void QGCApplication::criticalMessageBoxOnMainThread(const QString& title, const QString& msg)
{
void QGCApplication::criticalMessageBoxOnMainThread(const QString &title,
const QString &msg) {
#ifdef __mobile__
Q_UNUSED(title)
showMessage(msg);
......@@ -570,29 +622,43 @@ void QGCApplication::criticalMessageBoxOnMainThread(const QString& title, const
#endif
}
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
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();
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("").arg(toolbox()->settingsManager()->appSettings()->telemetryFileExtension);
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);
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());
QString error = tr("Unable to save telemetry log. Error copying "
"telemetry to '%1': '%2'.")
.arg(saveFilePath)
.arg(tempFile.errorString());
#ifndef __mobile__
QGCMessageBox::warning(tr("Telemetry Save Error"), error);
#else
......@@ -603,19 +669,20 @@ void QGCApplication::saveTelemetryLogOnMainThread(QString tempLogfile)
QFile::remove(tempLogfile);
}
void QGCApplication::checkTelemetrySavePathOnMainThread(void)
{
// This is called with an active vehicle so don't pop message boxes which holds ui thread
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)
{
bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox) {
QString errorTitle = tr("Telemetry save error");
QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath();
QString saveDirPath =
_toolbox->settingsManager()->appSettings()->telemetrySavePath();
if (saveDirPath.isEmpty()) {
QString error = tr("Unable to save telemetry log. Application save directory is not set.");
QString error = tr(
"Unable to save telemetry log. Application save directory is not set.");
#ifndef __mobile__
if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error);
......@@ -631,7 +698,9 @@ bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox)
QDir saveDir(saveDirPath);
if (!saveDir.exists()) {
QString error = tr("Unable to save telemetry log. Telemetry save directory \"%1\" does not exist.").arg(saveDirPath);
QString error = tr("Unable to save telemetry log. Telemetry save directory "
"\"%1\" does not exist.")
.arg(saveDirPath);
#ifndef __mobile__
if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error);
......@@ -647,14 +716,13 @@ bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox)
return true;
}
void QGCApplication::_loadCurrentStyleSheet(void)
{
void QGCApplication::_loadCurrentStyleSheet(void) {
#ifndef __mobile__
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.
// 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();
......@@ -663,7 +731,11 @@ void QGCApplication::_loadCurrentStyleSheet(void)
success = false;
}
if (success && !_toolbox->settingsManager()->appSettings()->indoorPalette()->rawValue().toBool()) {
if (success && !_toolbox->settingsManager()
->appSettings()
->indoorPalette()
->rawValue()
.toBool()) {
// Load the slave light stylesheet.
QFile styleSheet(_lightStyleFile);
if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
......@@ -683,15 +755,14 @@ void QGCApplication::_loadCurrentStyleSheet(void)
#endif
}
void QGCApplication::reportMissingParameter(int componentId, const QString& name)
{
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)
{
void QGCApplication::_missingParamsDisplay(void) {
if (_missingParams.count()) {
QString params;
foreach (const QString &name, _missingParams) {
......@@ -703,21 +774,23 @@ void QGCApplication::_missingParamsDisplay(void)
}
_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));
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()
{
QObject *QGCApplication::_rootQmlObject() {
#ifdef __mobile__
if(_qmlAppEngine && _qmlAppEngine->rootObjects().size())
if (_qmlAppEngine && _qmlAppEngine->rootObjects().size())
return _qmlAppEngine->rootObjects()[0];
return nullptr;
#else
MainWindow * mainWindow = MainWindow::instance();
MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) {
return mainWindow->rootQmlObject();
} else if (runningUnitTests()){
} else if (runningUnitTests()) {
// Unit test can run without a main window
return nullptr;
} else {
......@@ -727,24 +800,26 @@ QObject* QGCApplication::_rootQmlObject()
#endif
}
void QGCApplication::showMessage(const QString& message)
{
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)) {
if (message.startsWith(QStringLiteral("PreArm")) ||
message.startsWith(QStringLiteral("preflight"), Qt::CaseInsensitive)) {
return;
}
QObject* rootQmlObject = _rootQmlObject();
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));
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
} 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 {
......@@ -752,35 +827,35 @@ void QGCApplication::showMessage(const QString& message)
}
}
void QGCApplication::showSetupView(void)
{
if(_rootQmlObject()) {
void QGCApplication::showSetupView(void) {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "showSetupView");
}
}
void QGCApplication::qmlAttemptWindowClose(void)
{
if(_rootQmlObject()) {
void QGCApplication::qmlAttemptWindowClose(void) {
if (_rootQmlObject()) {
QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose");
}
}
bool QGCApplication::isInternetAvailable()
{
bool QGCApplication::isInternetAvailable() {
return getQGCMapEngine()->isInternetActive();
}
void QGCApplication::_checkForNewVersion(void)
{
void QGCApplication::_checkForNewVersion(void) {
#ifndef __mobile__
if (!_runningUnitTests) {
if (_parseVersionText(applicationVersion(), _majorVersion, _minorVersion, _buildVersion)) {
QString versionCheckFile = toolbox()->corePlugin()->stableVersionCheckFileUrl();
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);
connect(_currentVersionDownload, &QGCFileDownload::downloadFinished,
this, &QGCApplication::_currentVersionDownloadFinished);
connect(_currentVersionDownload, &QGCFileDownload::error, this,
&QGCApplication::_currentVersionDownloadError);
_currentVersionDownload->download(versionCheckFile);
}
}
......@@ -788,8 +863,8 @@ void QGCApplication::_checkForNewVersion(void)
#endif
}
void QGCApplication::_currentVersionDownloadFinished(QString remoteFile, QString localFile)
{
void QGCApplication::_currentVersionDownloadFinished(QString remoteFile,
QString localFile) {
Q_UNUSED(remoteFile);
#ifdef __mobile__
......@@ -806,8 +881,14 @@ void QGCApplication::_currentVersionDownloadFinished(QString remoteFile, QString
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()));
(_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()));
}
}
}
......@@ -816,14 +897,14 @@ void QGCApplication::_currentVersionDownloadFinished(QString remoteFile, QString
#endif
}
void QGCApplication::_currentVersionDownloadError(QString errorMsg)
{
void QGCApplication::_currentVersionDownloadError(QString errorMsg) {
Q_UNUSED(errorMsg);
_currentVersionDownload->deleteLater();
}
bool QGCApplication::_parseVersionText(const QString& versionString, int& majorVersion, int& minorVersion, int& buildVersion)
{
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) {
......@@ -836,21 +917,20 @@ bool QGCApplication::_parseVersionText(const QString& versionString, int& majorV
return false;
}
void QGCApplication::_onGPSConnect()
{
void QGCApplication::_onGPSConnect() {
_gpsRtkFactGroup->connected()->setRawValue(true);
}
void QGCApplication::_onGPSDisconnect()
{
void QGCApplication::_onGPSDisconnect() {
_gpsRtkFactGroup->connected()->setRawValue(false);
}
void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM, double latitude, double longitude, float altitude, bool valid, bool active)
{
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->currentAccuracy()->setRawValue(accuracyMM / 1000.0);
_gpsRtkFactGroup->currentLatitude()->setRawValue(latitude);
_gpsRtkFactGroup->currentLongitude()->setRawValue(longitude);
_gpsRtkFactGroup->currentAltitude()->setRawValue(altitude);
......@@ -858,20 +938,17 @@ void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM, doubl
_gpsRtkFactGroup->active()->setRawValue(active);
}
void QGCApplication::_gpsNumSatellites(int numSatellites)
{
void QGCApplication::_gpsNumSatellites(int numSatellites) {
_gpsRtkFactGroup->numSatellites()->setRawValue(numSatellites);
}
QString QGCApplication::cachedParameterMetaDataFile(void)
{
QString QGCApplication::cachedParameterMetaDataFile(void) {
QSettings settings;
QDir parameterDir = QFileInfo(settings.fileName()).dir();
return parameterDir.filePath(QStringLiteral("ParameterFactMetaData.xml"));
}
QString QGCApplication::cachedAirframeMetaDataFile(void)
{
QString QGCApplication::cachedAirframeMetaDataFile(void) {
QSettings settings;
QDir airframeDir = QFileInfo(settings.fileName()).dir();
return airframeDir.filePath(QStringLiteral("PX4AirframeFactMetaData.xml"));
......
......@@ -146,6 +146,8 @@ QmlObjectListModel *WimaMeasurementArea::tiles() {
return &this->_tileData.tiles;
}
QVector<int> WimaMeasurementArea::progress() { return this->_progress; }
const QmlObjectListModel *WimaMeasurementArea::tiles() const {
return &this->_tileData.tiles;
}
......@@ -226,6 +228,17 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
return false;
}
}
bool WimaMeasurementArea::setProgress(const QVector<int> &p) {
if (!_calculating) {
if (p.size() == this->tiles()->count() && this->_progress != p) {
this->_progress = p;
emit progressChanged();
return true;
}
}
return false;
}
//!
//! \brief WimaMeasurementArea::doUpdate
//! \pre WimaMeasurementArea::deferUpdate must be called first, don't call
......@@ -312,6 +325,8 @@ void WimaMeasurementArea::deferUpdate() {
this->_timer.stop();
}
if (this->_tileData.size() > 0) {
this->_progress.clear();
emit this->progressChanged();
this->_tileData.clear();
emit this->tilesChanged();
}
......
......@@ -41,6 +41,7 @@ public:
Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT)
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
// Overrides from WimaPolygon
QString mapVisualQML(void) const;
......@@ -53,6 +54,7 @@ public:
Fact *minTransectLength();
Fact *showTiles();
QmlObjectListModel *tiles();
QVector<int> progress();
const QmlObjectListModel *tiles() const;
const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate
const TileData &tileData() const;
......@@ -80,8 +82,10 @@ public:
signals:
void tilesChanged();
void maxTilesChanged();
void progressChanged();
public slots:
bool setProgress(const QVector<int> &p);
private slots:
void doUpdate();
......@@ -108,4 +112,6 @@ private:
TileData _tileData;
QFutureWatcher<DataPtr> _watcher;
bool _calculating;
QVector<int> _progress;
};
......@@ -45,13 +45,21 @@ public:
void stop();
void setTileData(const TileData &tileData);
bool hasTileData(const TileData &tileData) const;
void setAutoPublish(bool ap);
void setHoldProgress(bool hp);
NemoInterface::NemoStatus status();
bool holdProgress();
void publishTileData();
NemoInterface::STATUS status();
QVector<int> progress();
bool running();
private:
bool doTopicServiceSetup();
void loop();
static STATUS heartbeatToStatus(
const ros_bridge::messages::nemo_msgs::heartbeat::Heartbeat &hb);
//!
//! \brief Publishes tilesENU
//! \pre this->tilesENUMutex must be locked
......@@ -69,25 +77,41 @@ private:
QGeoCoordinate ENUOrigin;
mutable std::shared_timed_mutex ENUOriginMutex;
QNemoProgress qProgress;
QNemoProgress qProgressHolded;
mutable std::shared_timed_mutex progressMutex;
QNemoHeartbeat heartbeat;
NemoInterface::STATUS status_;
TimePoint nextTimeout;
mutable std::shared_timed_mutex heartbeatMutex;
mutable std::shared_timed_mutex statusMutex;
// Not protected data.
TileData tileData;
// Internals
bool running;
std::atomic_bool running_;
std::atomic_bool holdProgress_;
std::atomic_bool topicServiceSetupDone;
ROSBridgePtr pRosBridge;
QTimer loopTimer;
NemoInterface *parent;
};
using StatusMap = std::map<NemoInterface::STATUS, QString>;
StatusMap statusMap{
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::NOT_CONNECTED, "Not Connected"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::HEARTBEAT_DETECTED, "Heartbeat Detected"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::TIMEOUT, "Timeout"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::INVALID_HEARTBEAT, "Error"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::WEBSOCKET_DETECTED, "Websocket Detected")};
NemoInterface::Impl::Impl(NemoInterface *p)
: nextTimeout(TimePoint::max()), running(false),
topicServiceSetupDone(false), parent(p) {
: status_(STATUS::NOT_CONNECTED), nextTimeout(TimePoint::max()),
running_(false), holdProgress_(false), topicServiceSetupDone(false),
parent(p) {
// ROS Bridge.
WimaSettings *wimaSettings =
......@@ -117,9 +141,15 @@ NemoInterface::Impl::Impl(NemoInterface *p)
this->loopTimer.start(EVENT_TIMER_INTERVAL);
}
void NemoInterface::Impl::start() { this->running = true; }
void NemoInterface::Impl::start() {
this->running_ = true;
emit this->parent->runningChanged();
}
void NemoInterface::Impl::stop() { this->running = false; }
void NemoInterface::Impl::stop() {
this->running_ = false;
emit this->parent->runningChanged();
}
void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->tileData = tileData;
......@@ -135,7 +165,6 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->ENUOrigin = tile->coordinateList().first();
const auto &origin = this->ENUOrigin;
this->tilesENU.polygons().clear();
bool error = false;
for (int i = 0; i < tileData.tiles.count(); ++i) {
obj = tileData.tiles.get(i);
tile = qobject_cast<const SnakeTile *>(obj);
......@@ -145,16 +174,9 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->tilesENU.polygons().push_back(std::move(tileENU));
} else {
qWarning() << "NemoInterface::Impl::setTileData(): nullptr.";
error = true;
break;
}
}
if (!error && this->running && this->topicServiceSetupDone) {
this->publishENUOrigin();
this->publishTilesENU();
} else {
qWarning() << "NemoInterface::Impl::setTileData(): first tile empty.";
}
} else {
qWarning() << "NemoInterface::Impl::setTileData(): nullptr.";
}
......@@ -166,20 +188,52 @@ bool NemoInterface::Impl::hasTileData(const TileData &tileData) const {
return this->tileData == tileData;
}
NemoInterface::NemoStatus NemoInterface::Impl::status() {
SharedLock lk(this->heartbeatMutex);
return NemoInterface::NemoStatus(heartbeat.status());
void NemoInterface::Impl::setHoldProgress(bool hp) {
if (this->holdProgress_ != hp) {
this->holdProgress_ = hp;
emit this->parent->holdProgressChanged();
if (!this->holdProgress_) {
UniqueLock lk(this->progressMutex);
if (this->qProgress != this->qProgressHolded) {
this->qProgressHolded = this->qProgress;
lk.unlock();
emit this->parent->progressChanged();
}
}
}
}
bool NemoInterface::Impl::holdProgress() { return this->holdProgress_.load(); }
void NemoInterface::Impl::publishTileData() {
std::lock(this->ENUOriginMutex, this->tilesENUMutex);
UniqueLock lk1(this->ENUOriginMutex, std::adopt_lock);
UniqueLock lk2(this->tilesENUMutex, std::adopt_lock);
if (this->tilesENU.polygons().size() > 0 && this->running_ &&
this->topicServiceSetupDone) {
this->publishENUOrigin();
this->publishTilesENU();
}
}
NemoInterface::STATUS NemoInterface::Impl::status() {
SharedLock lk(this->statusMutex);
return status_;
}
QVector<int> NemoInterface::Impl::progress() {
SharedLock lk(this->progressMutex);
return this->qProgress.progress();
return this->qProgressHolded.progress();
}
bool NemoInterface::Impl::running() { return this->running_.load(); }
bool NemoInterface::Impl::doTopicServiceSetup() {
using namespace ros_bridge::messages;
// Publish snake tiles.
// snake tiles.
{
SharedLock lk(this->tilesENUMutex);
......@@ -188,16 +242,14 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
this->pRosBridge->advertiseTopic(
"/snake/tiles",
jsk_recognition_msgs::polygon_array::messageType().c_str());
this->publishTilesENU();
}
// Publish snake origin.
// snake origin.
{
SharedLock lk(this->ENUOriginMutex);
this->pRosBridge->advertiseTopic(
"/snake/origin", geographic_msgs::geo_point::messageType().c_str());
this->publishENUOrigin();
}
// Subscribe nemo progress.
......@@ -211,35 +263,23 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
UniqueLock lk3(this->ENUOriginMutex, std::adopt_lock);
int requiredSize = this->tilesENU.polygons().size();
auto hold = this->holdProgress_.load();
auto &progressMsg = this->qProgress;
if (!nemo_msgs::progress::fromJson(*pDoc, progressMsg) ||
progressMsg.progress().size() !=
requiredSize) { // Some error occured.
progressMsg.progress().clear();
// Publish snake origin.
JsonDocUPtr jOrigin(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
bool ret = geographic_msgs::geo_point::toJson(
this->ENUOrigin, *jOrigin, jOrigin->GetAllocator());
Q_ASSERT(ret);
(void)ret;
this->pRosBridge->publish(std::move(jOrigin), "/snake/origin");
// Publish snake tiles.
JsonDocUPtr jSnakeTiles(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
ret = jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, *jSnakeTiles, jSnakeTiles->GetAllocator());
Q_ASSERT(ret);
(void)ret;
this->pRosBridge->publish(std::move(jSnakeTiles), "/snake/tiles");
qgcApp()->showMessage("Invalid progress message received.");
} else if (!hold) {
this->qProgressHolded = this->qProgress;
}
lk1.unlock();
lk2.unlock();
lk3.unlock();
if (!hold) {
emit this->parent->progressChanged();
}
});
// Subscribe /nemo/heartbeat.
......@@ -247,13 +287,16 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
"/nemo/heartbeat",
/* callback */ [this](JsonDocUPtr pDoc) {
// auto start = std::chrono::high_resolution_clock::now();
UniqueLock lk(this->heartbeatMutex);
auto &heartbeatMsg = this->heartbeat;
nemo_msgs::heartbeat::Heartbeat heartbeatMsg;
UniqueLock lk(this->statusMutex);
if (!nemo_msgs::heartbeat::fromJson(*pDoc, heartbeatMsg)) {
heartbeatMsg.setStatus(integral(NemoStatus::InvalidHeartbeat));
this->nextTimeout = TimePoint::max();
status_ = STATUS::INVALID_HEARTBEAT;
} else {
status_ = heartbeatToStatus(heartbeatMsg);
}
if (status_ == STATUS::INVALID_HEARTBEAT) {
this->nextTimeout = TimePoint::max();
} else if (status_ == STATUS::HEARTBEAT_DETECTED) {
this->nextTimeout =
std::chrono::high_resolution_clock::now() + timeoutInterval;
}
......@@ -309,20 +352,29 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
}
void NemoInterface::Impl::loop() {
// Check ROS Bridge status and do setup if necessary.
if (this->running) {
if (this->running_) {
if (!this->pRosBridge->isRunning()) {
this->pRosBridge->start();
} else if (this->pRosBridge->isRunning() && this->pRosBridge->connected() &&
!this->topicServiceSetupDone) {
if (this->doTopicServiceSetup())
if (this->doTopicServiceSetup()) {
this->topicServiceSetupDone = true;
UniqueLock lk(this->statusMutex);
this->status_ = STATUS::WEBSOCKET_DETECTED;
lk.unlock();
emit this->parent->statusChanged();
}
} else if (this->pRosBridge->isRunning() &&
!this->pRosBridge->connected() && this->topicServiceSetupDone) {
this->pRosBridge->reset();
this->pRosBridge->start();
this->topicServiceSetupDone = false;
UniqueLock lk(this->statusMutex);
this->status_ = STATUS::TIMEOUT;
lk.unlock();
emit this->parent->statusChanged();
}
} else if (this->pRosBridge->isRunning()) {
this->pRosBridge->reset();
......@@ -330,17 +382,29 @@ void NemoInterface::Impl::loop() {
}
// Check if heartbeat timeout occured.
if (this->running && this->topicServiceSetupDone) {
UniqueLock lk(this->heartbeatMutex);
if (this->running_ && this->topicServiceSetupDone) {
UniqueLock lk(this->statusMutex);
if (this->nextTimeout != TimePoint::max() &&
this->nextTimeout < std::chrono::high_resolution_clock::now()) {
this->heartbeat.setStatus(integral(NemoStatus::Timeout));
if (this->pRosBridge->isRunning() && this->pRosBridge->connected()) {
this->status_ = STATUS::WEBSOCKET_DETECTED;
} else {
this->status_ = STATUS::TIMEOUT;
}
lk.unlock();
emit this->parent->statusChanged();
}
}
}
NemoInterface::STATUS NemoInterface::Impl::heartbeatToStatus(
const ros_bridge::messages::nemo_msgs::heartbeat::Heartbeat &hb) {
if (STATUS(hb.status()) == STATUS::HEARTBEAT_DETECTED)
return STATUS::HEARTBEAT_DETECTED;
else
return STATUS::INVALID_HEARTBEAT;
}
void NemoInterface::Impl::publishTilesENU() {
using namespace ros_bridge::messages;
JsonDocUPtr jSnakeTiles(
......@@ -374,7 +438,13 @@ void NemoInterface::start() { this->pImpl->start(); }
void NemoInterface::stop() { this->pImpl->stop(); }
void NemoInterface::publishTileData(const TileData &tileData) {
void NemoInterface::publishTileData() { this->pImpl->publishTileData(); }
void NemoInterface::requestProgress() {
qWarning() << "NemoInterface::requestProgress(): dummy.";
}
void NemoInterface::setTileData(const TileData &tileData) {
this->pImpl->setTileData(tileData);
}
......@@ -382,8 +452,26 @@ bool NemoInterface::hasTileData(const TileData &tileData) const {
return this->pImpl->hasTileData(tileData);
}
NemoInterface::NemoStatus NemoInterface::status() const {
void NemoInterface::setHoldProgress(bool hp) {
this->pImpl->setHoldProgress(hp);
}
int NemoInterface::status() const { return integral(this->pImpl->status()); }
NemoInterface::STATUS NemoInterface::statusEnum() const {
return this->pImpl->status();
}
QString NemoInterface::statusString() const {
return statusMap.at(this->pImpl->status());
}
QVector<int> NemoInterface::progress() const { return this->pImpl->progress(); }
QString NemoInterface::editorQml() {
return QStringLiteral("NemoInterface.qml");
}
bool NemoInterface::running() { return this->pImpl->running(); }
bool NemoInterface::holdProgress() { return this->pImpl->holdProgress(); }
......@@ -13,28 +13,48 @@ class NemoInterface : public QObject {
using PImpl = std::unique_ptr<Impl>;
public:
enum class NemoStatus {
NotConnected = 0,
Connected = 1,
Timeout = -1,
InvalidHeartbeat = -2
enum class STATUS {
NOT_CONNECTED = 0,
HEARTBEAT_DETECTED = 1,
WEBSOCKET_DETECTED = 2,
TIMEOUT = -1,
INVALID_HEARTBEAT = -2
};
explicit NemoInterface(QObject *parent = nullptr);
~NemoInterface() override;
void start();
void stop();
Q_PROPERTY(int status READ status NOTIFY statusChanged)
Q_PROPERTY(QString statusString READ statusString NOTIFY statusChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString editorQml READ editorQml CONSTANT)
Q_PROPERTY(bool running READ running NOTIFY runningChanged)
Q_PROPERTY(bool holdProgress READ holdProgress WRITE setHoldProgress NOTIFY
holdProgressChanged)
void publishTileData(const TileData &tileData);
Q_INVOKABLE void start();
Q_INVOKABLE void stop();
Q_INVOKABLE void publishTileData();
Q_INVOKABLE void requestProgress();
void setTileData(const TileData &tileData);
bool hasTileData(const TileData &tileData) const;
void setAutoPublish(bool ap);
void setHoldProgress(bool hp);
NemoStatus status() const;
int status() const;
STATUS statusEnum() const;
QString statusString() const;
QVector<int> progress() const;
QString editorQml();
bool running();
bool holdProgress();
signals:
void statusChanged();
void progressChanged();
void runningChanged();
void holdProgressChanged();
private:
PImpl pImpl;
......
......@@ -58,9 +58,8 @@ WimaController::WimaController(QObject *parent)
_areaInterface(&_measurementArea, &_serviceArea, &_corridor,
&_joinedArea),
_WMSettings(), _defaultWM(_WMSettings, _areaInterface),
_snakeWM(_WMSettings, _areaInterface),
_rtlWM(_WMSettings, _areaInterface),
_currentWM(&_defaultWM), _WMList{&_defaultWM, &_snakeWM, &_rtlWM},
_currentWM(&_defaultWM), _WMList{&_defaultWM, &_rtlWM},
_metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)),
_enableWimaController(settingsGroup,
......@@ -78,7 +77,6 @@ WimaController::WimaController(QObject *parent)
_arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]),
_altitude(settingsGroup, _metaDataMap[altitudeName]),
_lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
_nemoInterface(this),
_batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {
// Set up facts for waypoint manager.
......@@ -97,14 +95,6 @@ WimaController::WimaController(QObject *parent)
connect(&_altitude, &Fact::rawValueChanged, this,
&WimaController::_updateAltitude);
// Nemo stuff.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
// Init waypoint managers.
bool value;
size_t overlap = _overlapWaypoints.rawValue().toUInt(&value);
......@@ -124,35 +114,6 @@ WimaController::WimaController(QObject *parent)
connect(&_eventTimer, &QTimer::timeout, this,
&WimaController::_eventTimerHandler);
_eventTimer.start(EVENT_TIMER_INTERVAL);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
// Enable/disable snake.
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_enableSnakeChangedHandler);
_enableSnakeChangedHandler();
connect(&_enableWimaController, &Fact::rawValueChanged, [this] {
if (!this->_enableWimaController.rawValue().toBool()) {
this->_enableSnake.setCookedValue(QVariant(false));
}
});
// Snake Waypoint Manager.
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_switchToSnakeWaypointManager);
_switchToSnakeWaypointManager(_enableSnake.rawValue());
// Routing
connect(&_routingThread, &RoutingThread::result, this,
&WimaController::_storeRoute);
connect(&_routingThread, &RoutingThread::calculatingChanged, this,
&WimaController::snakeCalcInProgressChanged);
}
PlanMasterController *WimaController::masterController() {
......@@ -226,17 +187,13 @@ double WimaController::phaseDuration() const {
}
int WimaController::nemoStatus() const {
return integral(_nemoInterface.status());
return integral(NemoInterface::STATUS::NOT_CONNECTED);
}
QString WimaController::nemoStatusString() const {
return _nemoStatusMap.at(nemoStatus());
}
bool WimaController::snakeCalcInProgress() const {
return _routingThread.calculating();
}
void WimaController::setMasterController(PlanMasterController *masterC) {
_masterController = masterC;
_WMSettings.setMasterController(masterC);
......@@ -390,7 +347,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
// reset visual items
_areas.clear();
_defaultWM.clear();
_snakeWM.clear();
_measurementArea = WimaMeasurementAreaData();
_serviceArea = WimaServiceAreaData();
_corridor = WimaCorridorData();
......@@ -463,9 +419,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
emit visualItemsChanged();
emit snakeTilesChanged();
// Copy raw transects.
this->_rawTransects = planData->transects();
// Copy missionItems.
auto tempMissionItems = planData->missionItems();
if (tempMissionItems.size() < 1) {
......@@ -474,7 +427,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
}
for (auto *item : tempMissionItems) {
_snakeWM.push_back(item->coordinate());
_defaultWM.push_back(item->coordinate());
}
_WMSettings.setHomePosition(QGeoCoordinate(
......@@ -484,36 +436,14 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
Q_ASSERT(false);
return false;
}
if (!_snakeWM.reset()) {
Q_ASSERT(false);
return false;
}
if (_currentWM == &_defaultWM || _currentWM == &_snakeWM) {
if (_currentWM == &_defaultWM) {
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit waypointPathChanged();
emit currentWaypointPathChanged();
}
// Publish tiles, set progress if necessary.
if (!this->_nemoInterface.hasTileData(this->_measurementArea.tileData())) {
if (_enableSnake.rawValue().toBool()) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
this->_measurementArea.progress() =
QVector<int>(this->_measurementArea.tiles()->count(), 0);
emit nemoProgressChanged();
} else if (this->_enableSnake.rawValue().toBool()) {
const auto progress = this->_nemoInterface.progress();
if (progress.size() == this->_measurementArea.tiles()->count()) {
this->_measurementArea.progress() = std::move(progress);
emit nemoProgressChanged();
this->_updateRoute();
}
}
_planDataValid = true;
return true;
}
......@@ -790,226 +720,3 @@ void WimaController::_initSmartRTL() {
&WimaController::_initSmartRTL);
}
}
void WimaController::_storeRoute(RoutingThread::PtrRoutingData data) {
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now();
#endif
// Copy waypoints to waypoint manager.
_snakeWM.clear();
if (data->solutionVector.size() > 0 &&
data->solutionVector.front().size() > 0) {
// Store route.
const auto &transectsENU = data->transects;
const auto &solution = data->solutionVector.front();
const auto &route = solution.front();
const auto &path = route.path;
const auto &info = route.info;
// Find index of first waypoint.
std::size_t idxFirst = 0;
const auto &infoFirst = info.front();
const auto &firstTransect = transectsENU[infoFirst.index];
const auto &firstWaypoint =
infoFirst.reversed ? firstTransect.back() : firstTransect.front();
double th = 0.001;
for (std::size_t i = 0; i < path.size(); ++i) {
auto dist = bg::distance(path[i], firstWaypoint);
if (dist < th) {
idxFirst = i;
break;
}
}
// Find index of last waypoint.
std::size_t idxLast = path.size() - 1;
const auto &infoLast = info.back();
const auto &lastTransect = transectsENU[infoLast.index];
const auto &lastWaypoint =
infoLast.reversed ? lastTransect.front() : lastTransect.back();
for (long i = path.size() - 1; i >= 0; --i) {
auto dist = bg::distance(path[i], lastWaypoint);
if (dist < th) {
idxLast = i;
break;
}
}
// Convert to geo coordinates and append to waypoint manager.
const auto &ori = this->_origin;
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto &vertex = path[i];
QGeoCoordinate c;
snake::fromENU(ori, vertex, c);
_snakeWM.push_back(c);
}
// Do update.
this->_snakeWM.update(); // this can take a while (ca. 200ms)
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
#ifdef SNAKE_SHOW_TIME
auto end = std::chrono::high_resolution_clock::now();
std::cout << "WimaController::_threadFinishedHandler(): waypoints: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< " ms" << std::endl;
#endif
}
void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
if (variant.value<bool>()) {
_switchWaypointManager(_snakeWM);
} else {
_switchWaypointManager(_defaultWM);
}
}
void WimaController::_progressChangedHandler() {
const auto progress = this->_nemoInterface.progress();
if (this->_measurementArea.tiles()->count() == progress.size()) {
this->_measurementArea.progress() = std::move(progress);
emit nemoProgressChanged();
this->_updateRoute();
} else if (_planDataValid) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
}
void WimaController::_enableSnakeChangedHandler() {
if (this->_enableSnake.rawValue().toBool()) {
qDebug() << "WimaController: enabling snake.";
_switchWaypointManager(_snakeWM);
this->_nemoInterface.start();
if (_planDataValid) {
if (!this->_nemoInterface.hasTileData(
this->_measurementArea.tileData())) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
}
} else {
qDebug() << "WimaController: disabling snake.";
_switchWaypointManager(_defaultWM);
this->_nemoInterface.stop();
}
}
void WimaController::_updateRoute() {
// precondtion
if (_planDataValid && this->_joinedArea.coordinateList().size() > 0) {
const auto progress = this->_nemoInterface.progress();
const auto *tiles = this->_measurementArea.tiles();
// precondtion
if (tiles->count() > 0 && progress.size() == tiles->count() &&
this->_rawTransects.size() > 0 &&
this->_joinedArea.coordinateList().size() > 0) {
// Fetch tiles and convert to ENU.
this->_origin = this->_joinedArea.coordinateList().first();
this->_origin.setAltitude(0);
const auto &origin = this->_origin;
auto pTiles = std::make_shared<std::vector<snake::FPolygon>>();
std::size_t numTiles = 0;
for (int i = 0; i < progress.size(); ++i) {
if (progress[i] == 100) {
++numTiles;
const auto *obj = tiles->get(i);
const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
snake::FPolygon t;
snake::areaToEnu(origin, tile->coordinateList(), t);
pTiles->push_back(std::move(t));
} else {
return;
}
}
}
if (numTiles > 0) {
// Fetch safe area and convert to ENU.
RoutingParameter par;
auto safeArea = this->_joinedArea.coordinateList();
for (auto &v : safeArea) {
v.setAltitude(0);
}
auto &safeAreaENU = par.safeArea;
snake::areaToEnu(origin, safeArea, safeAreaENU);
const auto &depot = this->_serviceArea.depot();
snake::FPoint depotENU;
snake::toENU(origin, depot, depotENU);
// Fetch geo transects and convert to ENU.
const auto &geoTransects = this->_rawTransects;
auto pUnclippedTransects = std::make_shared<snake::Transects>();
for (auto &geoTransect : geoTransects) {
snake::FLineString t;
for (auto &geoVertex : geoTransect) {
snake::FPoint v;
snake::toENU(origin, geoVertex, v);
t.push_back(v);
}
pUnclippedTransects->push_back(t);
}
std::size_t minLength = 1; // meter
qWarning() << "using minLength dummy lkjfdslooij";
auto generator = [depotENU, pUnclippedTransects, pTiles,
minLength](snake::Transects &transects) -> bool {
// Convert transects to clipper path.
vector<ClipperLib::Path> transectsClipper;
for (const auto &t : *pUnclippedTransects) {
ClipperLib::Path path;
for (const auto &v : t) {
ClipperLib::IntPoint c{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)};
path.push_back(c);
}
transectsClipper.push_back(std::move(path));
}
// Add transects to clipper.
ClipperLib::Clipper clipper;
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
// Add tiles to clipper.
vector<ClipperLib::Path> tilesClipper;
for (const auto &t : *pTiles) {
ClipperLib::Path path;
for (const auto &v : t.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
tilesClipper.push_back(std::move(path));
}
clipper.AddPaths(tilesClipper, ClipperLib::ptClip, true);
// Clip transects.
ClipperLib::PolyTree clippedTransecs;
clipper.Execute(ClipperLib::ctDifference, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Extract transects from PolyTree and convert them to
// BoostLineString
transects.push_back(snake::FLineString{depotENU});
for (const auto &child : clippedTransecs.Childs) {
snake::FLineString transect;
for (const auto &v : child->Contour) {
snake::FPoint c{static_cast<double>(v.X) / CLIPPER_SCALE,
static_cast<double>(v.Y) / CLIPPER_SCALE};
transect.push_back(c);
}
if (bg::length(transect) >= minLength) {
transects.push_back(std::move(transect));
}
}
if (transects.size() > 1) {
return true;
} else {
return false;
}
}; // generator
this->_routingThread.route(par, generator);
} else {
this->_storeRoute(RoutingThread::PtrRoutingData(new RoutingData()));
}
}
}
}
......@@ -67,12 +67,9 @@ public:
double phaseDuration READ phaseDuration NOTIFY phaseDurationChanged)
// Snake
Q_PROPERTY(Fact *enableSnake READ enableSnake CONSTANT)
Q_PROPERTY(int nemoStatus READ nemoStatus NOTIFY nemoStatusChanged)
Q_PROPERTY(QString nemoStatusString READ nemoStatusString NOTIFY
nemoStatusStringChanged)
Q_PROPERTY(bool snakeCalcInProgress READ snakeCalcInProgress NOTIFY
snakeCalcInProgressChanged)
Q_PROPERTY(
QmlObjectListModel *snakeTiles READ snakeTiles NOTIFY snakeTilesChanged)
Q_PROPERTY(QVariantList snakeTileCenterPoints READ snakeTileCenterPoints
......@@ -102,15 +99,12 @@ public:
Fact *flightSpeed(void);
Fact *arrivalReturnSpeed(void);
Fact *altitude(void);
// Snake settings facts.
Fact *enableSnake(void) { return &_enableSnake; }
// Snake data.
QmlObjectListModel *snakeTiles(void);
QVariantList snakeTileCenterPoints(void);
QVector<int> nemoProgress(void);
int nemoStatus(void) const;
QString nemoStatusString(void) const;
bool snakeCalcInProgress(void) const;
bool uploadOverrideRequired(void) const;
bool vehicleHasLowBattery(void) const;
......@@ -153,8 +147,6 @@ public:
static const char *flightSpeedName;
static const char *arrivalReturnSpeedName;
static const char *altitudeName;
static const char *snakeLineDistanceName;
static const char *snakeMinTransectLengthName;
signals:
// Controllers.
......@@ -176,7 +168,6 @@ signals:
void phaseDistanceChanged(void);
void phaseDurationChanged(void);
// Snake.
void snakeCalcInProgressChanged(void);
void snakeTilesChanged(void);
void nemoProgressChanged(void);
void nemoStatusChanged(void);
......@@ -207,12 +198,7 @@ private slots:
void _initSmartRTL();
void _smartRTLCleanUp(bool flying);
// Snake.
void _storeRoute(RoutingThread::PtrRoutingData data);
void _switchWaypointManager(WaypointManager::ManagerBase &manager);
void _switchToSnakeWaypointManager(QVariant variant);
void _progressChangedHandler();
void _enableSnakeChangedHandler();
void _updateRoute();
// Periodic tasks.
void _eventTimerHandler(void);
......@@ -234,7 +220,6 @@ private:
WaypointManager::AreaInterface _areaInterface;
WaypointManager::Settings _WMSettings; // Waypoint Manager Settings
WaypointManager::DefaultManager _defaultWM;
WaypointManager::DefaultManager _snakeWM;
WaypointManager::RTLManager _rtlWM;
WaypointManager::ManagerBase *_currentWM;
using ManagerList = QList<WaypointManager::ManagerBase *>;
......@@ -262,7 +247,6 @@ private:
SettingsFact _flightSpeed; // mission flight speed
SettingsFact _arrivalReturnSpeed; // arrival and return path speed
SettingsFact _altitude; // mission altitude
SettingsFact _enableSnake; // Enable Snake (see snake.h)
// Smart RTL.
QTimer _smartRTLTimer;
......@@ -271,13 +255,8 @@ private:
// Waypoint statistics.
double _measurementPathLength; // the lenght of the phase in meters
// Snake
QList<QList<QGeoCoordinate>> _rawTransects;
NemoInterface _nemoInterface;
using StatusMap = std::map<int, QString>;
static StatusMap _nemoStatusMap;
RoutingThread _routingThread;
QGeoCoordinate _origin;
// Periodic tasks.
QTimer _eventTimer;
......
......@@ -25,7 +25,8 @@ WimaPlaner::WimaPlaner(QObject *parent)
_currentAreaIndex(-1), _wimaBridge(nullptr), _mAreaChanged(true),
_sAreaChanged(true), _corridorChanged(true), _joinedArea(this),
_arrivalPathLength(0), _returnPathLength(0), _TSComplexItem(nullptr),
_surveyChanged(true), _synchronized(false), _needsUpdate(true) {
_surveyChanged(true), _synchronized(false), _needsUpdate(true),
_nemoInterface(this) {
connect(this, &WimaPlaner::currentPolygonIndexChanged, this,
&WimaPlaner::updatePolygonInteractivity);
......@@ -33,10 +34,14 @@ WimaPlaner::WimaPlaner(QObject *parent)
this->_mAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_measurementArea, &WimaMeasurementArea::tilesChanged, [this] {
this->_nemoInterface.setTileData(this->_measurementArea.tileData());
});
connect(&this->_serviceArea, &WimaArea::pathChanged, [this] {
this->_sAreaChanged = true;
this->setNeedsUpdate(true);
});
connect(&this->_serviceArea, &WimaServiceArea::depotChanged, [this] {
this->_sAreaChanged = true;
this->setNeedsUpdate(true);
......@@ -52,6 +57,11 @@ WimaPlaner::WimaPlaner(QObject *parent)
_autoLoadTimer.setSingleShot(true);
_autoLoadTimer.start(300);
#endif
// NemoInterface
connect(&this->_nemoInterface, &NemoInterface::progressChanged, [this] {
this->_measurementArea.setProgress(this->_nemoInterface.progress());
});
}
PlanMasterController *WimaPlaner::masterController() {
......@@ -95,6 +105,8 @@ QGeoCoordinate WimaPlaner::joinedAreaCenter() const {
WimaBridge *WimaPlaner::wimaBridge() { return _wimaBridge; }
NemoInterface *WimaPlaner::nemoInterface() { return &_nemoInterface; }
void WimaPlaner::setMasterController(PlanMasterController *masterC) {
_masterController = masterC;
emit masterControllerChanged();
......
......@@ -14,6 +14,8 @@
#include "Geometry/WimaServiceAreaData.h"
#include "WimaPlanData.h"
#include "Snake/NemoInterface.h"
#include "JsonHelper.h"
class MissionController;
......@@ -45,6 +47,7 @@ public:
Q_PROPERTY(QGeoCoordinate joinedAreaCenter READ joinedAreaCenter CONSTANT)
Q_PROPERTY(WimaBridge *wimaBridge READ wimaBridge WRITE setWimaBridge NOTIFY
wimaBridgeChanged)
Q_PROPERTY(NemoInterface *nemoInterface READ nemoInterface CONSTANT)
Q_PROPERTY(bool synchronized READ synchronized NOTIFY synchronizedChanged)
Q_PROPERTY(bool needsUpdate READ needsUpdate NOTIFY needsUpdateChanged)
......@@ -59,6 +62,7 @@ public:
QString fileExtension(void) const;
QGeoCoordinate joinedAreaCenter(void) const;
WimaBridge *wimaBridge(void);
NemoInterface *nemoInterface(void);
bool synchronized();
bool needsUpdate();
......@@ -161,4 +165,6 @@ private:
QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents
// seg. faults
#endif
NemoInterface _nemoInterface;
};
......@@ -110,25 +110,39 @@ Item {
// Add Snake tiles to the map
Component {
id: tileComponent
MapPolygon {
color: "transparent"
opacity: 1
border.color: "black"
border.width: 1
MapPolygon{
path: []
opacity: 0.6
z: 2
}
}
Repeater {
id: progressRepeater
property bool enable: areaItem.showTiles.value
model: enable ? areaItem.tiles : 0
function getColor(i) {
var progress = areaItem.progress[i]
if (progress < 25)
return "transparent"
if (progress < 50)
return "orange"
if (progress < 75)
return "yellow"
if (progress < 100)
return "greenyellow"
return "limegreen"
}
Item{
property var _tileComponent
function addVisuals() {
_tileComponent = tileComponent.createObject(map)
map.addMapItem(_tileComponent)
_tileComponent.path = object.path
_tileComponent.color = progressRepeater.getColor(index)
}
function removeVisuals() {
......
......@@ -155,7 +155,7 @@ Rectangle {
anchors.left: logoRow.right
anchors.right: uploadButton.visible ? uploadButton.left : parent.right
columnSpacing: 0
columns: 3
columns: 4
GridLayout {
columns: 8
......@@ -252,7 +252,7 @@ Rectangle {
rowSpacing: _rowSpacing
columnSpacing: _labelToValueSpacing
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: _batteryInfoAvailable
// visible: _batteryInfoAvailable
QGCLabel {
text: qsTr("Battery")
......@@ -268,7 +268,7 @@ Rectangle {
}
Item { width: 1; height: 1 }
/*
/*
FIXME: Swap point display is currently hidden since the code which calcs it doesn't work correctly
QGCLabel { text: qsTr("Swap waypoint:"); font.pointSize: _dataFontSize; }
QGCLabel {
......@@ -278,6 +278,72 @@ Rectangle {
}
*/
}
GridLayout {
columns: 3
rowSpacing: _rowSpacing
columnSpacing: _labelToValueSpacing
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
QGCLabel {
text: qsTr("ROS")
Layout.columnSpan: 3
font.pointSize: ScreenTools.smallFontPointSize
}
QGCCheckBox {
id: enableCheckbox
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: qsTr("Enable")
checked: nemo ? nemo.running : false
onCheckedChanged: {
if (nemo){
if (checked){
nemo.start()
} else {
nemo.stop()
}
checked = Qt.binding(function(){return nemo.running})
}
}
Layout.minimumWidth: _mediumValueWidth
}
QGCLabel {
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: nemo ? nemo.statusString : ""
font.pointSize: _dataFontSize
Layout.minimumWidth: _mediumValueWidth
visible: enableCheckbox.checked
Layout.columnSpan: 2
}
QGCCheckBox {
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: qsTr("Lock Progress")
checked: nemo ? nemo.lockProgress : false
visible: enableCheckbox.checked
onCheckedChanged: {
if (nemo){
if (checked){
nemo.lockProgress = true
} else {
nemo.lockProgress = false
}
checked = Qt.binding(function(){return nemo.lockProgress})
}
}
Layout.minimumWidth: _mediumValueWidth
}
}
}
QGCButton {
......
......@@ -54,6 +54,7 @@ QGCView {
property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
property var _wimaPlaner: wimaPlaner
property var _nemo: wimaPlaner.nemoInterface
property var _planMasterController: masterController
property var _missionController: _planMasterController.missionController
property var _visualItems: _missionController.visualItems
......@@ -702,6 +703,10 @@ QGCView {
name: qsTr("Update"),
iconSource: "/res/calculator.png"
},
{
name: qsTr("Publish"),
iconSource: "/res/calculator.png"
},
{
name: qsTr("Center"),
iconSource: "/qmlimages/MapCenter.svg",
......@@ -731,10 +736,13 @@ QGCView {
case 4:
wimaPlaner.update();
break
case 6:
editorMap.zoomLevel += 0.5
case 5:
_nemo.publishTileData();
break
case 7:
editorMap.zoomLevel += 0.5
break
case 8:
editorMap.zoomLevel -= 0.5
break
}
......
......@@ -4,59 +4,70 @@
#include <vector>
namespace ros_bridge {
//! @brief Namespace containing classes and methodes ros message generation.
namespace messages {
//! @brief Namespace containing classes and methodes for geometry_msgs generation.
//! @brief Namespace containing classes and methodes for geometry_msgs
//! generation.
namespace nemo_msgs {
//! @brief Namespace containing methodes for geometry_msgs/Point32 message generation.
//! @brief Namespace containing methodes for geometry_msgs/Point32 message
//! generation.
namespace progress {
std::string messageType();
//! @brief C++ representation of nemo_msgs/Progress message
template <class IntType = long, template <class, class...> class ContainterType = std::vector>
class GenericProgress{
template <class IntType = long,
template <class, class...> class ContainterType = std::vector>
class GenericProgress {
public:
GenericProgress() {}
GenericProgress(const ContainterType<IntType> &progress) : _progress(progress){}
GenericProgress(const GenericProgress &p) : _progress(p.progress()){}
GenericProgress(const ContainterType<IntType> &progress)
: _progress(progress) {}
GenericProgress(const GenericProgress &p) : _progress(p.progress()) {}
virtual const ContainterType<IntType> &progress(void) const {
return _progress;
}
virtual ContainterType<IntType> &progress(void) { return _progress; }
virtual const ContainterType<IntType> &progress(void) const {return _progress;}
virtual ContainterType<IntType> &progress(void) {return _progress;}
bool operator==(const GenericProgress &other) const {
return this->_progress == other._progress;
}
bool operator!=(const GenericProgress &other) const {
return !this->operator==(other);
}
protected:
ContainterType<IntType> _progress;
};
typedef GenericProgress<> Progress;
template <class ProgressType>
bool toJson(const ProgressType &p, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator)
{
bool toJson(const ProgressType &p, rapidjson::Value &value,
rapidjson::Document::AllocatorType &allocator) {
rapidjson::Value jProgress(rapidjson::kArrayType);
for(unsigned long i=0; i < std::uint64_t(p.progress().size()); ++i){
jProgress.PushBack(rapidjson::Value().SetInt(std::int32_t(p.progress()[i])), allocator);
for (unsigned long i = 0; i < std::uint64_t(p.progress().size()); ++i) {
jProgress.PushBack(rapidjson::Value().SetInt(std::int32_t(p.progress()[i])),
allocator);
}
value.AddMember("progress", jProgress, allocator);
return true;
}
template <class ProgressType>
bool fromJson(const rapidjson::Value &value, ProgressType &p)
{
if (!value.HasMember("progress") || !value["progress"].IsArray()){
bool fromJson(const rapidjson::Value &value, ProgressType &p) {
if (!value.HasMember("progress") || !value["progress"].IsArray()) {
assert(false);
return false;
}
const auto& jsonProgress = value["progress"];
const auto &jsonProgress = value["progress"];
unsigned long sz = jsonProgress.Size();
p.progress().clear();
p.progress().reserve(sz);
for (unsigned long i=0; i < sz; ++i)
for (unsigned long i = 0; i < sz; ++i)
p.progress().push_back(std::int32_t(jsonProgress[i].GetInt()));
return true;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment