diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index c5e4e10..fa2c4b2 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -474,6 +474,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/CameraSectionTest.h \
src/MissionManager/CorridorScanComplexItemTest.h \
src/MissionManager/FWLandingPatternTest.h \
+ src/MissionManager/MissionCommandTreeEditorTest.h \
src/MissionManager/MissionCommandTreeTest.h \
src/MissionManager/MissionControllerManagerTest.h \
src/MissionManager/MissionControllerTest.h \
@@ -520,6 +521,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/CameraSectionTest.cc \
src/MissionManager/CorridorScanComplexItemTest.cc \
src/MissionManager/FWLandingPatternTest.cc \
+ src/MissionManager/MissionCommandTreeEditorTest.cc \
src/MissionManager/MissionCommandTreeTest.cc \
src/MissionManager/MissionControllerManagerTest.cc \
src/MissionManager/MissionControllerTest.cc \
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 9373f9d..6136453 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -64,6 +64,7 @@
src/AnalyzeView/MAVLinkInspectorPage.qml
src/ui/preferences/MavlinkSettings.qml
src/Microhard/MicrohardSettings.qml
+ src/MissionManager/MissionCommandTreeEditorTestWindow.qml
src/PlanView/MissionSettingsEditor.qml
src/ui/preferences/MockLink.qml
src/ui/preferences/MockLinkSettings.qml
diff --git a/src/MissionManager/MissionCommandTreeEditorTest.cc b/src/MissionManager/MissionCommandTreeEditorTest.cc
new file mode 100644
index 0000000..08e8522
--- /dev/null
+++ b/src/MissionManager/MissionCommandTreeEditorTest.cc
@@ -0,0 +1,64 @@
+/****************************************************************************
+ *
+ * (c) 2009-2020 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#include "MissionCommandTreeEditorTest.h"
+#include "QGCApplication.h"
+#include "QGCCorePlugin.h"
+#include "SimpleMissionItem.h"
+#include "PlanMasterController.h"
+
+MissionCommandTreeEditorTest::MissionCommandTreeEditorTest(void)
+{
+
+}
+
+void MissionCommandTreeEditorTest::_testEditorsWorker(QGCMAVLink::FirmwareClass_t firmwareClass, QGCMAVLink::VehicleClass_t vehicleClass)
+{
+ QString firmwareClassString = QGCMAVLink::firmwareClassToString(firmwareClass).replace(" ", "");
+ QString vehicleClassString = QGCMAVLink::vehicleClassToString(vehicleClass).replace(" ", "");
+
+ AppSettings* appSettings = qgcApp()->toolbox()->settingsManager()->appSettings();
+ appSettings->offlineEditingFirmwareClass()->setRawValue(firmwareClass);
+ appSettings->offlineEditingVehicleClass()->setRawValue(vehicleClass);
+ PlanMasterController* masterController = new PlanMasterController();
+
+ FirmwarePlugin* firmwarePlugin = qgcApp()->toolbox()->firmwarePluginManager()->firmwarePluginForAutopilot(QGCMAVLink::firmwareClassToAutopilot(firmwareClass), QGCMAVLink::vehicleClassToMavType(vehicleClass));
+ if (firmwarePlugin->supportedMissionCommands().count() == 0) {
+ firmwarePlugin = qgcApp()->toolbox()->firmwarePluginManager()->firmwarePluginForAutopilot(QGCMAVLink::firmwareClassToAutopilot(QGCMAVLink::FirmwareClassPX4), QGCMAVLink::vehicleClassToMavType(vehicleClass));
+ }
+ int cColumns = firmwarePlugin->supportedMissionCommands().count();
+
+ QVariantList varSimpleItems;
+ for (MAV_CMD command: firmwarePlugin->supportedMissionCommands()) {
+ SimpleMissionItem* simpleItem = new SimpleMissionItem(masterController, false /* flyView */, false /* forLoad */, this);
+ simpleItem->setCommand(command);
+ varSimpleItems.append(QVariant::fromValue(simpleItem));
+ }
+
+ QQmlApplicationEngine* qmlAppEngine = qgcApp()->toolbox()->corePlugin()->createQmlApplicationEngine(this);
+ qmlAppEngine->rootContext()->setContextProperty("planMasterController", masterController);
+ qmlAppEngine->rootContext()->setContextProperty("missionItems", varSimpleItems);
+ qmlAppEngine->rootContext()->setContextProperty("cColumns", cColumns);
+ qmlAppEngine->rootContext()->setContextProperty("imagePath", QStringLiteral("/home/parallels/Downloads/%1-%2.png").arg(firmwareClassString).arg(vehicleClassString));
+ qmlAppEngine->load(QUrl(QStringLiteral("qrc:/qml/MissionCommandTreeEditorTestWindow.qml")));
+
+ QTest::qWait(1000);
+
+ delete qmlAppEngine;
+}
+
+void MissionCommandTreeEditorTest::testEditors(void)
+{
+ for (const QGCMAVLink::FirmwareClass_t& firmwareClass: QGCMAVLink::allFirmwareClasses()) {
+ for (const QGCMAVLink::VehicleClass_t& vehicleClass: QGCMAVLink::allVehicleClasses()) {
+ _testEditorsWorker(firmwareClass, vehicleClass);
+ }
+ }
+}
+
diff --git a/src/MissionManager/MissionCommandTreeEditorTest.h b/src/MissionManager/MissionCommandTreeEditorTest.h
new file mode 100644
index 0000000..e34f075
--- /dev/null
+++ b/src/MissionManager/MissionCommandTreeEditorTest.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+ *
+ * (c) 2009-2020 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include "UnitTest.h"
+
+/// This unit test is meant to be used stand-alone to generate images for each mission item editor for review
+class MissionCommandTreeEditorTest : public UnitTest
+{
+ Q_OBJECT
+
+public:
+ MissionCommandTreeEditorTest(void);
+
+private slots:
+ void testEditors(void);
+
+private:
+ void _testEditorsWorker(QGCMAVLink::FirmwareClass_t firmwareClass, QGCMAVLink::VehicleClass_t vehicleClass);
+};
diff --git a/src/MissionManager/MissionCommandTreeEditorTestWindow.qml b/src/MissionManager/MissionCommandTreeEditorTestWindow.qml
new file mode 100644
index 0000000..d8be76d
--- /dev/null
+++ b/src/MissionManager/MissionCommandTreeEditorTestWindow.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+ *
+ * (c) 2009-2020 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Controls 2.4
+import QtQuick.Dialogs 1.3
+import QtQuick.Layouts 1.11
+import QtQuick.Window 2.11
+
+import QGroundControl 1.0
+import QGroundControl.Palette 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.FlightDisplay 1.0
+import QGroundControl.FlightMap 1.0
+import QGroundControl.Controllers 1.0
+
+ApplicationWindow {
+ id: _root
+ visible: true
+ visibility: Qt.WindowFullScreen
+ color: qgcPal.window
+
+ property real editorWidth: ScreenTools.defaultFontPixelWidth * 30
+
+ QGCPalette { id: qgcPal; colorGroupEnabled: true }
+
+ Timer {
+ id: timer
+ interval: 100
+ onTriggered: {
+ var success = fullImage.grabToImage(function(result) { result.saveToFile(imagePath) })
+ console.log(success)
+ }
+ }
+
+ Component.onCompleted: timer.start()
+
+ Flow {
+ id: fullImage
+ anchors.fill: parent
+
+ Repeater {
+ model: missionItems
+
+ Column {
+ QGCLabel { text: modelData.commandName; color: "black" }
+
+ Loader {
+ id: editorLoader
+ source: modelData.editorQml
+
+ property var missionItem: modelData
+ property var masterController: planMasterController
+ property real availableWidth: editorWidth
+ }
+ }
+ }
+ }
+}
diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc
index c3b8356..27a7d54 100644
--- a/src/QGCApplication.cc
+++ b/src/QGCApplication.cc
@@ -590,18 +590,18 @@ void QGCApplication::_initCommon()
qmlRegisterSingletonType ("QGroundControl", 1, 0, "QGroundControl", qgroundcontrolQmlGlobalSingletonFactory);
qmlRegisterSingletonType ("QGroundControl.ScreenToolsController", 1, 0, "ScreenToolsController", screenToolsControllerSingletonFactory);
qmlRegisterSingletonType ("QGroundControl.ShapeFileHelper", 1, 0, "ShapeFileHelper", shapeFileHelperSingletonFactory);
-}
-
-bool QGCApplication::_initForNormalAppBoot()
-{
+ // Although this should really be in _initForNormalAppBoot putting it here allowws us to create unit tests which pop up more easily
if(QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) {
qWarning() << "Could not load /fonts/opensans font";
}
if(QFontDatabase::addApplicationFont(":/fonts/opensans-demibold") < 0) {
qWarning() << "Could not load /fonts/opensans-demibold font";
}
+}
+bool QGCApplication::_initForNormalAppBoot()
+{
QSettings settings;
_qmlAppEngine = toolbox()->corePlugin()->createQmlApplicationEngine(this);
diff --git a/src/comm/QGCMAVLink.cc b/src/comm/QGCMAVLink.cc
index a3d7149..24b2f81 100644
--- a/src/comm/QGCMAVLink.cc
+++ b/src/comm/QGCMAVLink.cc
@@ -9,6 +9,8 @@
#include "QGCMAVLink.h"
+#include
+
constexpr QGCMAVLink::FirmwareClass_t QGCMAVLink::FirmwareClassPX4;
constexpr QGCMAVLink::FirmwareClass_t QGCMAVLink::FirmwareClassArduPilot;
constexpr QGCMAVLink::FirmwareClass_t QGCMAVLink::FirmwareClassGeneric;
@@ -56,6 +58,20 @@ QGCMAVLink::FirmwareClass_t QGCMAVLink::firmwareClass(MAV_AUTOPILOT autopilot)
}
}
+QString QGCMAVLink::firmwareClassToString(FirmwareClass_t firmwareClass)
+{
+ switch (firmwareClass) {
+ case FirmwareClassPX4:
+ return QT_TRANSLATE_NOOP("Firmware Class", "PX4 Pro");
+ case FirmwareClassArduPilot:
+ return QT_TRANSLATE_NOOP("Firmware Class", "ArduPilot");
+ case FirmwareClassGeneric:
+ return QT_TRANSLATE_NOOP("Firmware Class", "Generic");
+ default:
+ return QT_TRANSLATE_NOOP("Firmware Class", "Unknown");
+ }
+}
+
bool QGCMAVLink::isFixedWing(MAV_TYPE mavType)
{
return vehicleClass(mavType) == VehicleClassFixedWing;
@@ -109,6 +125,26 @@ QGCMAVLink::VehicleClass_t QGCMAVLink::vehicleClass(MAV_TYPE mavType)
}
}
+QString QGCMAVLink::vehicleClassToString(VehicleClass_t vehicleClass)
+{
+ switch (vehicleClass) {
+ case VehicleClassFixedWing:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Fixed Wing");
+ case VehicleClassRoverBoat:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Rover-Boat");
+ case VehicleClassSub:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Sub");
+ case VehicleClassMultiRotor:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Multi-Rotor");
+ case VehicleClassVTOL:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "VTOL");
+ case VehicleClassGeneric:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Generic");
+ default:
+ return QT_TRANSLATE_NOOP("Vehicle Class", "Unknown");
+ }
+}
+
QString QGCMAVLink::mavResultToString(MAV_RESULT result)
{
switch (result) {
diff --git a/src/comm/QGCMAVLink.h b/src/comm/QGCMAVLink.h
index 78ea810..3450173 100644
--- a/src/comm/QGCMAVLink.h
+++ b/src/comm/QGCMAVLink.h
@@ -68,6 +68,7 @@ public:
static bool isGenericFirmwareClass (MAV_AUTOPILOT autopilot) { return !isPX4FirmwareClass(autopilot) && ! isArduPilotFirmwareClass(autopilot); }
static FirmwareClass_t firmwareClass (MAV_AUTOPILOT autopilot);
static MAV_AUTOPILOT firmwareClassToAutopilot(FirmwareClass_t firmwareClass) { return static_cast(firmwareClass); }
+ static QString firmwareClassToString (FirmwareClass_t firmwareClass);
static QList allFirmwareClasses (void);
static bool isFixedWing (MAV_TYPE mavType);
@@ -77,9 +78,10 @@ public:
static bool isVTOL (MAV_TYPE mavType);
static VehicleClass_t vehicleClass (MAV_TYPE mavType);
static MAV_TYPE vehicleClassToMavType (VehicleClass_t vehicleClass) { return static_cast(vehicleClass); }
+ static QString vehicleClassToString (VehicleClass_t vehicleClass);
static QList allVehicleClasses (void);
- static QString mavResultToString (MAV_RESULT result);
+ static QString mavResultToString (MAV_RESULT result);
};
class MavlinkFTP {
diff --git a/src/qgcunittest/UnitTest.cc b/src/qgcunittest/UnitTest.cc
index 0479092..65e202b 100644
--- a/src/qgcunittest/UnitTest.cc
+++ b/src/qgcunittest/UnitTest.cc
@@ -37,15 +37,6 @@ enum UnitTest::FileDialogType UnitTest::_fileDialogExpectedType = getOpenFileNam
int UnitTest::_missedFileDialogCount = 0;
UnitTest::UnitTest(void)
- : _linkManager (nullptr)
- , _mockLink (nullptr)
- , _mainWindow (nullptr)
- , _vehicle (nullptr)
- , _expectMissedFileDialog (false)
- , _expectMissedMessageBox (false)
- , _unitTestRun (false)
- , _initCalled (false)
- , _cleanupCalled (false)
{
}
@@ -59,9 +50,9 @@ UnitTest::~UnitTest()
}
}
-void UnitTest::_addTest(QObject* test)
+void UnitTest::_addTest(UnitTest* test)
{
- QList& tests = _testList();
+ QList& tests = _testList();
Q_ASSERT(!tests.contains(test));
@@ -74,9 +65,9 @@ void UnitTest::_unitTestCalled(void)
}
/// @brief Returns the list of unit tests.
-QList& UnitTest::_testList(void)
+QList& UnitTest::_testList(void)
{
- static QList tests;
+ static QList tests;
return tests;
}
@@ -84,8 +75,11 @@ int UnitTest::run(QString& singleTest)
{
int ret = 0;
- for (QObject* test: _testList()) {
+ for (UnitTest* test: _testList()) {
if (singleTest.isEmpty() || singleTest == test->objectName()) {
+ if (test->standalone() && singleTest.isEmpty()) {
+ continue;
+ }
QStringList args;
args << "*" << "-maxwarnings" << "0";
ret += QTest::qExec(test, args);
@@ -136,7 +130,6 @@ void UnitTest::cleanup(void)
_cleanupCalled = true;
_disconnectMockLink();
- _closeMainWindow();
// Keep in mind that any code below these QCOMPARE may be skipped if the compare fails
if (_expectMissedMessageBox) {
@@ -433,36 +426,6 @@ void UnitTest::_linkDeleted(LinkInterface* link)
}
}
-void UnitTest::_createMainWindow(void)
-{
- //-- TODO
-#if 0
- _mainWindow = MainWindow::_create();
- Q_CHECK_PTR(_mainWindow);
-#endif
-}
-
-void UnitTest::_closeMainWindow(bool cancelExpected)
-{
- //-- TODO
-#if 0
- if (_mainWindow) {
- QSignalSpy mainWindowSpy(_mainWindow, SIGNAL(mainWindowClosed()));
-
- _mainWindow->close();
-
- mainWindowSpy.wait(2000);
- QCOMPARE(mainWindowSpy.count(), cancelExpected ? 0 : 1);
-
- // This leaves enough time for any dangling Qml components to get cleaned up.
- // This prevents qWarning from bad references in Qml
- QTest::qWait(1000);
- }
-#else
- Q_UNUSED(cancelExpected);
-#endif
-}
-
QString UnitTest::createRandomFile(uint32_t byteCount)
{
QTemporaryFile tempFile;
diff --git a/src/qgcunittest/UnitTest.h b/src/qgcunittest/UnitTest.h
index 5a10245..a270ee7 100644
--- a/src/qgcunittest/UnitTest.h
+++ b/src/qgcunittest/UnitTest.h
@@ -26,13 +26,13 @@
#include "Fact.h"
#include "MissionItem.h"
-#define UT_REGISTER_TEST(className) static UnitTestWrapper className(#className);
+#define UT_REGISTER_TEST(className) static UnitTestWrapper className(#className, false);
+#define UT_REGISTER_TEST_STANDALONE(className) static UnitTestWrapper className(#className, true);
class QGCMessageBox;
class QGCQFileDialog;
class LinkManager;
class MockLink;
-class MainWindow;
class Vehicle;
class UnitTest : public QObject
@@ -82,8 +82,11 @@ public:
// @param Expected failure response flags
void checkExpectedFileDialog(int expectFailFlags = expectFailNoFailure);
+ bool standalone(void) { return _standalone; }
+ void setStandalone(bool standalone) { _standalone = standalone; }
+
/// @brief Adds a unit test to the list. Should only be called by UnitTestWrapper.
- static void _addTest(QObject* test);
+ static void _addTest(UnitTest* test);
/// Creates a file with random contents of the specified size.
/// @return Fully qualified path to created file
@@ -122,17 +125,14 @@ protected:
void _connectMockLink(MAV_AUTOPILOT autopilot = MAV_AUTOPILOT_PX4);
void _connectMockLinkNoInitialConnectSequence(void) { _connectMockLink(MAV_AUTOPILOT_INVALID); }
void _disconnectMockLink(void);
- void _createMainWindow(void);
- void _closeMainWindow(bool cancelExpected = false);
void _missionItemsEqual(MissionItem& actual, MissionItem& expected);
- LinkManager* _linkManager;
- MockLink* _mockLink;
- MainWindow* _mainWindow;
- Vehicle* _vehicle;
+ LinkManager* _linkManager = nullptr;
+ MockLink* _mockLink = nullptr;
+ Vehicle* _vehicle = nullptr;
- bool _expectMissedFileDialog; // true: expect a missed file dialog, used for internal testing
- bool _expectMissedMessageBox; // true: expect a missed message box, used for internal testing
+ bool _expectMissedFileDialog = false; // true: expect a missed file dialog, used for internal testing
+ bool _expectMissedMessageBox = false; // true: expect a missed message box, used for internal testing
private slots:
void _linkDeleted(LinkInterface* link);
@@ -185,7 +185,7 @@ private:
friend class QGCQFileDialog;
void _unitTestCalled(void);
- static QList& _testList(void);
+ static QList& _testList(void);
// Catch QGCMessageBox calls
static bool _messageBoxRespondedTo; ///< Message box was responded to
@@ -200,18 +200,20 @@ private:
static enum FileDialogType _fileDialogExpectedType; ///< type of file dialog expected to show
static int _missedFileDialogCount; ///< Count of file dialogs not checked with call to UnitTest::fileDialogWasDisplayed
- bool _unitTestRun; ///< true: Unit Test was run
- bool _initCalled; ///< true: UnitTest::_init was called
- bool _cleanupCalled; ///< true: UnitTest::_cleanup was called
+ bool _unitTestRun = false; ///< true: Unit Test was run
+ bool _initCalled = false; ///< true: UnitTest::_init was called
+ bool _cleanupCalled = false; ///< true: UnitTest::_cleanup was called
+ bool _standalone = false; ///< true: Only run when requested specifically from command line
};
template
class UnitTestWrapper {
public:
- UnitTestWrapper(const QString& name) :
- _unitTest(new T)
+ UnitTestWrapper(const QString& name, bool standalone)
+ : _unitTest(new T)
{
_unitTest->setObjectName(name);
+ _unitTest->setStandalone(standalone);
UnitTest::_addTest(_unitTest.data());
}
diff --git a/src/qgcunittest/UnitTestList.cc b/src/qgcunittest/UnitTestList.cc
index 86139c2..3086308 100644
--- a/src/qgcunittest/UnitTestList.cc
+++ b/src/qgcunittest/UnitTestList.cc
@@ -48,6 +48,7 @@
#include "RequestMessageTest.h"
#include "InitialConnectTest.h"
#include "FTPManagerTest.h"
+#include "MissionCommandTreeEditorTest.h"
UT_REGISTER_TEST(FactSystemTestGeneric)
UT_REGISTER_TEST(FactSystemTestPX4)
@@ -83,6 +84,7 @@ UT_REGISTER_TEST(TransectStyleComplexItemTest)
UT_REGISTER_TEST(QGCMapPolylineTest)
UT_REGISTER_TEST(CameraCalcTest)
UT_REGISTER_TEST(FWLandingPatternTest)
+UT_REGISTER_TEST_STANDALONE(MissionCommandTreeEditorTest)
// List of unit test which are currently disabled.
// If disabling a new test, include reason in comment.