Commit b35962d1 authored by dogmaphobic's avatar dogmaphobic

Merge branch 'master' into testQML

parents 9a1080ab 4de3a940
......@@ -36,8 +36,10 @@ Fork the QGC Repo
### Initialize submodules
After cloning or forking you will need to initialize and update the submodules using these commands in you qgroundcontrol source directory:
```
git submodule init
git submodule update
```
Each time you pull new source to your repository you should re-run "git submodule update" to get the latest submodules as well.
......@@ -61,14 +63,14 @@ Supported builds are 64 bit, built using the clang compiler.
Supported builds for Linux are 32 or 64-bit, built using gcc.
#### Install Qt5.3+ and SDL1.2 prerequistites
* For Ubuntu (requires 14.10 for Qt5.3): `sudo apt-get install qtcreator qttools5-dev qtbase5-dev qt5-default qtdeclarative5-dev libqt5serialport5-dev libqt5svg5-dev libqt5webkit5-dev libsdl1.2-dev build-essential libudev-dev`
* For Ubuntu (requires 14.10 for Qt5.3): `sudo apt-get install qtcreator qttools5-dev qtbase5-dev qt5-default qtdeclarative5-dev libqt5serialport5-dev libqt5svg5-dev libqt5webkit5-dev libsdl1.2-dev build-essential libudev-dev qml-module-qtgraphicaleffects`
* For Fedora: `sudo yum install qt-creator qt5-qtbase-devel qt5-qtdeclarative-devel qt5-qtserialport-devel qt5-qtsvg-devel qt5-qtwebkit-devel SDL-devel SDL-static systemd-devel`
* For Arch Linux: `pacman -Sy qtcreator qt5-base qt5-declarative qt5-serialport qt5-svg qt5-webkit`
##### Install Qt5.3+ from PPA
Note: Please be aware that the time of writing, Qt5.3 is unavailable in the official repositories Ubuntu 14.04/Mint 17.*. If it has become available since, please follow the instructions for installing Qt5.3 on Ubuntu.
* Add this PPA to your sources.list: `ppa:beineri/opt-qt532-trusty`
* Run the following in your terminal: `sudo apt-get update && sudo apt-get install qt53tools qt53base qt53declarative qt53serialport qt53svg qt53webkit`
* Run the following in your terminal: `sudo apt-get update && sudo apt-get install qt53tools qt53base qt53declarative qt53serialport qt53svg qt53webkit qt53quickcontrols qt53graphicaleffects`
* Next, set the environment variables by executing in the terminal: `source /opt/qt53/bin/qt53-env.sh` or copy and paste the contents to your `~/.profile` file to set them on login.
* Verify that the variables have been set: `echo $PATH && echo $QTDIR`. The output should read `/opt/qt53/bin:...` and `/opt/qt53`.
......
Subproject commit 42f1a37397335b3c4c96b0a41c73d85e80d54a60
Subproject commit 7ae438b86ea983e95af5f092e45a5d0f9d093c74
......@@ -208,8 +208,6 @@ ReleaseBuild {
}
}
QML_IMPORT_PATH = $$BASEDIR/qml
# qextserialport should not be used by general QGroundControl code. Use QSerialPort instead. This is only
# here to support special case Firmware Upgrade code.
include(libs/qextserialport/src/qextserialport.pri)
......@@ -273,7 +271,6 @@ INCLUDEPATH += \
FORMS += \
src/ui/MainWindow.ui \
src/ui/CommSettings.ui \
src/ui/SerialSettings.ui \
src/ui/UASControl.ui \
src/ui/UASList.ui \
......@@ -302,7 +299,6 @@ FORMS += \
src/ui/QGCMAVLinkLogPlayer.ui \
src/ui/QGCWaypointListMulti.ui \
src/ui/QGCUASFileViewMulti.ui \
src/ui/QGCUDPLinkConfiguration.ui \
src/ui/QGCTCPLinkConfiguration.ui \
src/ui/SettingsDialog.ui \
src/ui/map/QGCMapTool.ui \
......@@ -342,10 +338,12 @@ FORMS += \
src/ui/px4_configuration/QGCPX4MulticopterConfig.ui \
src/ui/px4_configuration/QGCPX4SensorCalibration.ui \
src/ui/px4_configuration/PX4RCCalibration.ui \
src/ui/px4_configuration/PX4FirmwareUpgrade.ui \
src/ui/QGCUASFileView.ui \
src/QGCQmlWidgetHolder.ui \
src/ui/QGCMapRCToParamDialog.ui \
src/ui/QGCLinkConfiguration.ui \
src/ui/QGCCommConfiguration.ui \
src/ui/QGCUDPLinkConfiguration.ui
HEADERS += \
src/MG.h \
......@@ -356,14 +354,12 @@ HEADERS += \
src/uas/UASManager.h \
src/comm/LinkManager.h \
src/comm/LinkInterface.h \
src/comm/SerialLinkInterface.h \
src/comm/SerialLink.h \
src/comm/ProtocolInterface.h \
src/comm/MAVLinkProtocol.h \
src/comm/QGCFlightGearLink.h \
src/comm/QGCJSBSimLink.h \
src/comm/QGCXPlaneLink.h \
src/ui/CommConfigurationWindow.h \
src/ui/SerialConfigurationWindow.h \
src/ui/MainWindow.h \
src/ui/uas/UASControlWidget.h \
......@@ -418,7 +414,6 @@ HEADERS += \
src/uas/QGCMAVLinkUASFactory.h \
src/ui/QGCWaypointListMulti.h \
src/ui/QGCUASFileViewMulti.h \
src/ui/QGCUDPLinkConfiguration.h \
src/ui/QGCTCPLinkConfiguration.h \
src/ui/SettingsDialog.h \
src/uas/QGCUASParamManager.h \
......@@ -479,9 +474,6 @@ HEADERS += \
src/ui/px4_configuration/QGCPX4SensorCalibration.h \
src/ui/px4_configuration/PX4RCCalibration.h \
src/ui/px4_configuration/RCValueWidget.h \
src/ui/px4_configuration/PX4Bootloader.h \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.h \
src/ui/px4_configuration/PX4FirmwareUpgrade.h \
src/uas/UASManagerInterface.h \
src/uas/QGCUASParamManagerInterface.h \
src/uas/QGCUASFileManager.h \
......@@ -499,6 +491,10 @@ HEADERS += \
src/ui/QGCParamTreeWidget.h \
src/ui/QGCMapRCToParamDialog.h \
src/QGCDockWidget.h \
src/ui/QGCLinkConfiguration.h \
src/comm/LinkConfiguration.h \
src/ui/QGCCommConfiguration.h \
src/ui/QGCUDPLinkConfiguration.h
SOURCES += \
src/main.cc \
......@@ -512,7 +508,6 @@ SOURCES += \
src/comm/QGCFlightGearLink.cc \
src/comm/QGCJSBSimLink.cc \
src/comm/QGCXPlaneLink.cc \
src/ui/CommConfigurationWindow.cc \
src/ui/SerialConfigurationWindow.cc \
src/ui/MainWindow.cc \
src/ui/uas/UASControlWidget.cc \
......@@ -565,7 +560,6 @@ SOURCES += \
src/uas/QGCMAVLinkUASFactory.cc \
src/ui/QGCWaypointListMulti.cc \
src/ui/QGCUASFileViewMulti.cc \
src/ui/QGCUDPLinkConfiguration.cc \
src/ui/QGCTCPLinkConfiguration.cc \
src/ui/SettingsDialog.cc \
src/uas/QGCUASParamManager.cc \
......@@ -624,9 +618,6 @@ SOURCES += \
src/ui/px4_configuration/QGCPX4SensorCalibration.cc \
src/ui/px4_configuration/PX4RCCalibration.cc \
src/ui/px4_configuration/RCValueWidget.cc \
src/ui/px4_configuration/PX4Bootloader.cc \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc \
src/ui/px4_configuration/PX4FirmwareUpgrade.cc \
src/uas/QGCUASFileManager.cc \
src/ui/QGCUASFileView.cc \
src/CmdLineOptParser.cc \
......@@ -641,6 +632,10 @@ SOURCES += \
src/ui/QGCParamTreeWidget.cpp \
src/ui/QGCMapRCToParamDialog.cpp \
src/QGCDockWidget.cc \
src/ui/QGCLinkConfiguration.cc \
src/comm/LinkConfiguration.cc \
src/ui/QGCCommConfiguration.cc \
src/ui/QGCUDPLinkConfiguration.cc
#
# Unit Test specific configuration goes here
......@@ -681,7 +676,9 @@ HEADERS += \
src/qgcunittest/MavlinkLogTest.h \
src/FactSystem/FactSystemTestBase.h \
src/FactSystem/FactSystemTestPX4.h \
src/FactSystem/FactSystemTestGeneric.h
src/FactSystem/FactSystemTestGeneric.h \
src/QmlControls/QmlTestWidget.h \
src/VehicleSetup/SetupViewTest.h \
SOURCES += \
src/qgcunittest/UnitTest.cc \
......@@ -705,12 +702,19 @@ SOURCES += \
src/qgcunittest/MavlinkLogTest.cc \
src/FactSystem/FactSystemTestBase.cc \
src/FactSystem/FactSystemTestPX4.cc \
src/FactSystem/FactSystemTestGeneric.cc
src/FactSystem/FactSystemTestGeneric.cc \
src/QmlControls/QmlTestWidget.cc \
src/VehicleSetup/SetupViewTest.cc \
}
#
# AutoPilot Plugin Support
#
INCLUDEPATH += \
src/VehicleSetup
FORMS += \
src/VehicleSetup/ParameterEditor.ui \
src/ui/QGCPX4VehicleConfig.ui \
......@@ -721,6 +725,9 @@ HEADERS+= \
src/VehicleSetup/SetupView.h \
src/VehicleSetup/ParameterEditor.h \
src/VehicleSetup/VehicleComponent.h \
src/VehicleSetup/FirmwareUpgradeController.h \
src/VehicleSetup/PX4Bootloader.h \
src/VehicleSetup/PX4FirmwareUpgradeThread.h \
src/AutoPilotPlugins/AutoPilotPluginManager.h \
src/AutoPilotPlugins/AutoPilotPlugin.h \
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h \
......@@ -739,6 +746,9 @@ SOURCES += \
src/VehicleSetup/SetupView.cc \
src/VehicleSetup/ParameterEditor.cc \
src/VehicleSetup/VehicleComponent.cc \
src/VehicleSetup/FirmwareUpgradeController.cc \
src/VehicleSetup/PX4Bootloader.cc \
src/VehicleSetup/PX4FirmwareUpgradeThread.cc \
src/AutoPilotPlugins/AutoPilotPluginManager.cc \
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc \
src/AutoPilotPlugins/Generic/GenericParameterFacts.cc \
......
......@@ -239,20 +239,26 @@
<qresource prefix="/qml">
<file alias="test.qml">src/test.qml</file>
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="QGroundControl/FactControls/qmldir">qml/QGroundControl/FactControls/qmldir</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">qml/QGroundControl/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">qml/QGroundControl/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">qml/QGroundControl/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/Controls/qmldir">qml/QGroundControl/Controls/qmldir</file>
<file alias="QGroundControl/Controls/SetupButton.qml">qml/QGroundControl/Controls/SetupButton.qml</file>
<file alias="QGroundControl/Controls/qmldir">src/QmlControls/qmldir</file>
<file alias="QGroundControl/Controls/SetupButton.qml">src/QmlControls/SetupButton.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCRadioButton.qml">src/QmlControls/QGCRadioButton.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
<file alias="QGroundControl/Controls/QGCLabel.qml">src/QmlControls/QGCLabel.qml</file>
<file alias="octo_x.png">files/images/px4/airframes/octo_x.png</file>
<file alias="px4fmu_2.x.png">files/images/px4/boards/px4fmu_2.x.png</file>
<file alias="SetupViewButtons.qml">src/VehicleSetup/SetupViewButtons.qml</file>
<file alias="VehicleSummary.qml">src/VehicleSetup/VehicleSummary.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="SafetyComponent.qml">src/AutoPilotPlugins/PX4/SafetyComponent.qml</file>
......
Module QGroundControl.Controls
SetupButton 1.0 SetupButton.qml
\ No newline at end of file
......@@ -30,6 +30,9 @@
/// @brief Parameters which signal a change in setupComplete state
static const char* triggerParams[] = { "SYS_AUTOSTART", NULL };
#if 0
// Broken by latest mavlink module changes. Not used yet. Comment out for now.
// Discussing mavlink fix.
struct mavType {
int type;
const char* description;
......@@ -58,17 +61,28 @@ static const struct mavType mavTypeInfo[] = {
{ MAV_TYPE_ONBOARD_CONTROLLER, "Onbard companion controller" },
{ MAV_TYPE_VTOL_DUOROTOR, "Two-rotor VTOL" },
{ MAV_TYPE_VTOL_QUADROTOR, "Quad-rotor VTOL" },
{ MAV_TYPE_VTOL_RESERVED1, "Reserved" },
{ MAV_TYPE_VTOL_RESERVED2, "Reserved" },
{ MAV_TYPE_VTOL_RESERVED3, "Reserved" },
{ MAV_TYPE_VTOL_RESERVED4, "Reserved" },
{ MAV_TYPE_VTOL_RESERVED5, "Reserved" },
{ MAV_TYPE_GIMBAL, "Gimbal" },
};
static size_t cMavTypes = sizeof(mavTypeInfo) / sizeof(mavTypeInfo[0]);
#endif
AirframeComponent::AirframeComponent(UASInterface* uas, AutoPilotPlugin* autopilot, QObject* parent) :
PX4Component(uas, autopilot, parent),
_name(tr("Airframe"))
{
#if 0
// Broken by latest mavlink module changes. Not used yet. Comment out for now.
// Discussing mavlink fix.
Q_UNUSED(mavTypeInfo); // Keeping this around for later use
// Validate that our mavTypeInfo array hasn't gotten out of sync
qDebug() << cMavTypes << MAV_TYPE_ENUM_END;
Q_ASSERT(cMavTypes == MAV_TYPE_ENUM_END);
static const int mavTypes[] = {
......@@ -92,13 +106,20 @@ AirframeComponent::AirframeComponent(UASInterface* uas, AutoPilotPlugin* autopil
MAV_TYPE_KITE,
MAV_TYPE_ONBOARD_CONTROLLER,
MAV_TYPE_VTOL_DUOROTOR,
MAV_TYPE_VTOL_QUADROTOR
MAV_TYPE_VTOL_QUADROTOR,
MAV_TYPE_VTOL_RESERVED1,
MAV_TYPE_VTOL_RESERVED2,
MAV_TYPE_VTOL_RESERVED3,
MAV_TYPE_VTOL_RESERVED4,
MAV_TYPE_VTOL_RESERVED5,
MAV_TYPE_GIMBAL,
};
Q_UNUSED(mavTypes); // Keeping this around for later use
for (size_t i=0; i<cMavTypes; i++) {
Q_ASSERT(mavTypeInfo[i].type == mavTypes[i]);
}
#endif
}
QString AirframeComponent::name(void) const
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
Rectangle {
QGCPalette { id: palette; colorGroup: QGCPalette.Active }
......
......@@ -31,12 +31,17 @@
// These two list must be kept in sync
/// @brief Parameters which signal a change in setupComplete state
static const char* triggerParams[] = { "SENS_MAG_XOFF", "SENS_GYRO_XOFF", "SENS_ACC_XOFF", "SENS_DPRES_OFF", NULL };
static const char* triggerParamsV1[] = { "SENS_MAG_XOFF", "SENS_GYRO_XOFF", "SENS_ACC_XOFF", "SENS_DPRES_OFF", NULL };
static const char* triggerParamsV2[] = { "CAL_MAG0_ID", "CAL_GYRO0_ID", "CAL_ACC0_ID", "SENS_DPRES_OFF", NULL };
SensorsComponent::SensorsComponent(UASInterface* uas, AutoPilotPlugin* autopilot, QObject* parent) :
PX4Component(uas, autopilot, parent),
_name(tr("Sensors"))
{
// Determine what set of parameters are available. This is a temporary hack for now. Will need real parameter
// mapping in the future.
QVariant value;
_paramsV1 = _paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "SENS_MAG_XOFF", value);
}
QString SensorsComponent::name(void) const
......@@ -97,14 +102,18 @@ QString SensorsComponent::setupStateDescription(void) const
const char** SensorsComponent::setupCompleteChangedTriggerList(void) const
{
return triggerParams;
return _paramsV1 ? triggerParamsV1 : triggerParamsV2;
}
QStringList SensorsComponent::paramFilterList(void) const
{
QStringList list;
list << "SENS_*";
if (_paramsV1) {
list << "SENS_*";
} else {
list << "CAL_*";
}
return list;
}
......
......@@ -55,6 +55,7 @@ public:
private:
const QString _name;
QVariantList _summaryItems;
bool _paramsV1;
};
#endif
......@@ -15,7 +15,8 @@ Column {
Text {
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: autopilot.parameters["SENS_MAG_XOFF"].value == 0.0 ? "Setup required" : "Ready"
property bool setupRequiredValue: autopilot.parameters["SENS_MAG_XOFF"] ? autopilot.parameters["SENS_MAG_XOFF"].value : autopilot.parameters["CAL_MAG0_ID"].value
text: setupRequiredValue == 0 ? "Setup required" : "Ready"
}
}
......@@ -26,7 +27,8 @@ Column {
Text {
horizontalAlignment: Text.AlignRight;
width: parent.width - gyro.contentWidth;
text: autopilot.parameters["SENS_GYRO_XOFF"].value == 0.0 ? "Setup required" : "Ready"
property bool setupRequiredValue: autopilot.parameters["SENS_GYRO_XOFF"] ? autopilot.parameters["SENS_GYRO_XOFF"].value : autopilot.parameters["CAL_GYRO0_ID"].value
text: setupRequiredValue == 0 ? "Setup required" : "Ready"
}
}
......@@ -37,7 +39,8 @@ Column {
Text {
horizontalAlignment: Text.AlignRight;
width: parent.width - accel.contentWidth;
text: autopilot.parameters["SENS_ACC_XOFF"].value == 0.0 ? "Setup required" : "Ready"
property bool setupRequiredValue: autopilot.parameters["SENS_ACC_XOFF"] ? autopilot.parameters["SENS_ACC_XOFF"].value : autopilot.parameters["CAL_ACC0_ID"].value
text: setupRequiredValue == 0 ? "Setup required" : "Ready"
}
}
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
CheckBox {
property Fact fact: Fact { value: 0 }
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
Label {
property Fact fact: Fact { value: "FactLabel" }
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
TextField {
property Fact fact: Fact { value: 0 }
......
......@@ -28,7 +28,6 @@
#include "UASManager.h"
#include "QGCApplication.h"
#include "VehicleComponent.h"
#include "QGCPalette.h"
#include <QtQml>
......@@ -44,7 +43,6 @@ FactSystem::FactSystem(QObject* parent) :
// FIXME: Where should these go?
qmlRegisterUncreatableType<VehicleComponent>(_factSystemQmlUri, 1, 0, "VehicleComponent", "Can only reference VehicleComponent");
qmlRegisterType<QGCPalette>(_factSystemQmlUri, 1, 0, "QGCPalette");
}
FactSystem::~FactSystem()
......
This diff is collapsed.
......@@ -23,6 +23,7 @@
#include "QGCFileDialog.h"
#include "QGCApplication.h"
#include <QRegularExpression>
#include "MainWindow.h"
#ifdef QT_DEBUG
#include "UnitTest.h"
......@@ -90,6 +91,7 @@ QString QGCFileDialog::getSaveFileName(
const QString& dir,
const QString& filter,
const QString& defaultSuffix,
bool strict,
Options options)
{
_validate(options);
......@@ -100,28 +102,104 @@ QString QGCFileDialog::getSaveFileName(
} else
#endif
{
QString defaultSuffixCopy(defaultSuffix);
QFileDialog dlg(parent, caption, dir, filter);
dlg.setAcceptMode(QFileDialog::AcceptSave);
if (options) {
dlg.setOptions(options);
}
if (!defaultSuffix.isEmpty()) {
QString suffixCopy(defaultSuffix);
if (!defaultSuffixCopy.isEmpty()) {
//-- Make sure dot is not present
if (suffixCopy.startsWith(".")) {
suffixCopy.remove(0,1);
if (defaultSuffixCopy.startsWith(".")) {
defaultSuffixCopy.remove(0,1);
}
dlg.setDefaultSuffix(suffixCopy);
dlg.setDefaultSuffix(defaultSuffixCopy);
}
if (dlg.exec()) {
if (dlg.selectedFiles().count()) {
return dlg.selectedFiles().first();
while (true) {
if (dlg.exec()) {
if (dlg.selectedFiles().count()) {
QString result = dlg.selectedFiles().first();
//-- If we don't care about the extension, just return it
if (!strict) {
return result;
} else {
//-- We must enforce the file extension
QFileInfo fi(result);
QString userSuffix(fi.suffix());
if (_validateExtension(filter, userSuffix)) {
return result;
}
//-- Do we have a default extension?
if (defaultSuffixCopy.isEmpty()) {
//-- We don't, so get the first one in the filter
defaultSuffixCopy = _getFirstExtensionInFilter(filter);
}
//-- If this is set to strict, we have to have a default extension
Q_ASSERT(defaultSuffixCopy.isEmpty() == false);
//-- Forcefully append our desired extension
result += ".";
result += defaultSuffixCopy;
//-- Check and see if this new file already exists
fi.setFile(result);
if (fi.exists()) {
//-- Ask user what to do
QMessageBox msgBox(
QMessageBox::Warning,
tr("File Exists"),
tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()),
QMessageBox::Cancel,
parent);
msgBox.addButton(QMessageBox::Retry);
QPushButton *overwriteButton = msgBox.addButton(tr("Replace"), QMessageBox::ActionRole);
msgBox.setDefaultButton(QMessageBox::Retry);
msgBox.setWindowModality(Qt::ApplicationModal);
if (msgBox.exec() == QMessageBox::Retry) {
continue;
} else if (msgBox.clickedButton() == overwriteButton) {
return result;
}
} else {
return result;
}
}
}
}
break;
}
return QString("");
}
}
/// @brief Make sure filename is using one of the valid extensions defined in the filter
bool QGCFileDialog::_validateExtension(const QString& filter, const QString& extension) {
QRegularExpression re("(\\*\\.\\w+)");
QRegularExpressionMatchIterator i = re.globalMatch(filter);
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
if (match.hasMatch()) {
//-- Compare "foo" with "*.foo"
if(extension == match.captured(0).mid(2)) {
return true;
}
}
}
return false;
}
/// @brief Returns first extension found in filter
QString QGCFileDialog::_getFirstExtensionInFilter(const QString& filter) {
QRegularExpression re("(\\*\\.\\w+)");
QRegularExpressionMatchIterator i = re.globalMatch(filter);
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
if (match.hasMatch()) {
//-- Return "foo" from "*.foo"
return match.captured(0).mid(2);
}
}
return QString("");
}
/// @brief Validates and updates the parameters for the file dialog calls
void QGCFileDialog::_validate(Options& options)
{
......
......@@ -54,12 +54,12 @@ public:
//! Static helper that will return an existing directory selected by the user.
/*!
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The chosen path or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getExistingDirectory">QFileDialog::getExistingDirectory()</a>
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The chosen path or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getExistingDirectory">QFileDialog::getExistingDirectory()</a>
*/
static QString getExistingDirectory(
QWidget* parent = 0,
......@@ -69,13 +69,13 @@ public:
//! Static helper that invokes a File Open dialog where the user can select a file to be opened.
/*!
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The full path and filename to be opened or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getOpenFileName">QFileDialog::getOpenFileName()</a>
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The full path and filename to be opened or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getOpenFileName">QFileDialog::getOpenFileName()</a>
*/
static QString getOpenFileName(
QWidget* parent = 0,
......@@ -86,13 +86,13 @@ public:
//! Static helper that invokes a File Open dialog where the user can select one or more files to be opened.
/*!
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return A <a href="http://qt-project.org/doc/qt-5/qstringlist.html">QStringList</a> object containing zero or more files to be opened.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getOpenFileNames">QFileDialog::getOpenFileNames()</a>
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return A <a href="http://qt-project.org/doc/qt-5/qstringlist.html">QStringList</a> object containing zero or more files to be opened.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getOpenFileNames">QFileDialog::getOpenFileNames()</a>
*/
static QStringList getOpenFileNames(
QWidget* parent = 0,
......@@ -103,16 +103,20 @@ public:
//! Static helper that invokes a File Save dialog where the user can select a directory and enter a filename to be saved.
/*!
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] defaultSuffix Specifies a string that will be added to the filename if it has no suffix already. The suffix is typically used to indicate the file type (e.g. "txt" indicates a text file).
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The full path and filename to be used to save the file or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getSaveFileName">QFileDialog::getSaveFileName()</a>
@remark If a default suffix is given, it will be appended to the filename if the user does not enter one themselves. That is, if the user simply enters \e foo and the default suffix is set to \e bar,
the returned filename will be \e foo.bar. However, if the user specifies a suffix, none will be added. That is, if the user enters \e foo.txt, that's what you will receive in return.
@param[in] parent The parent QWidget.
@param[in] caption The caption displayed at the top of the dialog.
@param[in] dir The initial directory shown to the user.
@param[in] filter The filter used for selecting the file type.
@param[in] defaultSuffix Specifies a string that will be added to the filename if it has no suffix already. The suffix is typically used to indicate the file type (e.g. "txt" indicates a text file).
@param[in] strict Makes the default suffix mandatory. Only files with those extensions will be allowed.
@param[in] options Set the various options that affect the look and feel of the dialog.
@return The full path and filename to be used to save the file or \c QString("") if none.
@sa <a href="http://qt-project.org/doc/qt-5/qfiledialog.html#getSaveFileName">QFileDialog::getSaveFileName()</a>
@remark If a default suffix is given, it will be appended to the filename if the user does not enter one themselves. That is, if the user simply enters \e foo and the default suffix is set to \e bar,
the returned filename will be \e foo.bar. However, if the user specifies a suffix, the \e strict flag will determine what is done. If the user enters \e foo.txt and \e strict is false, the function
returns \e foo.txt (no suffix enforced). If \e strict is true however, the default suffix is appended no matter what. In the case above, the function will return \e foo.txt.bar (suffix enforced).
@remark If \e strict is set and the file name given by the user is renamed (the \e foo.txt.bar example above), the function will check and see if the file already exists. If that's the case, it will
ask the user if they want to overwrite it.
*/
static QString getSaveFileName(
QWidget* parent = 0,
......@@ -120,6 +124,7 @@ public:
const QString& dir = QString(),
const QString& filter = QString(),
const QString& defaultSuffix = QString(),
bool strict = false,
Options options = 0);
private slots:
......@@ -128,7 +133,9 @@ private slots:
int exec(void) { return QGCFileDialog::exec(); }
private:
static void _validate(Options& options);
static void _validate(Options& options);
static bool _validateExtension(const QString& filter, const QString& extension);
static QString _getFirstExtensionInFilter(const QString& filter);
};
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef QGCMESSAGEBOX_H
......@@ -40,34 +40,34 @@
/// @author Don Gagne <don@thegagnes.com>
class QGCMessageBox : public QMessageBox {
public:
static StandardButton critical(const QString& title, const QString& text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton, QWidget* parent = NULL)
{ return _messageBox(QMessageBox::Critical, title, text, buttons, defaultButton, parent); }
static StandardButton information(const QString & title, const QString& text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton, QWidget* parent = NULL)
{ return _messageBox(QMessageBox::Information, title, text, buttons, defaultButton, parent); }
static StandardButton question(const QString& title, const QString& text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton, QWidget* parent = NULL)
{ return _messageBox(QMessageBox::Question, title, text, buttons, defaultButton, parent); }
static StandardButton warning(const QString& title, const QString& text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton, QWidget* parent = NULL)
{ return _messageBox(QMessageBox::Warning, title, text, buttons, defaultButton, parent); }
private slots:
/// @brief The exec slot is private becasue when only want QGCMessageBox users to use the static methods. Otherwise it will break
/// unit testing.
int exec(void) { return QMessageBox::exec(); }
private:
static QWidget* _validateParameters(StandardButtons buttons, StandardButton* defaultButton, QWidget* parent)
{
// This is an obsolete bit which unit tests use for signalling. It should not be used in regular code.
Q_ASSERT(!(buttons & QMessageBox::Escape));
// If there is more than one button displayed, make sure a default button is set. Without this unit test code
// will not be able to respond to unexpected message boxes.
unsigned int bits = static_cast<unsigned int>(buttons);
int buttonCount = 0;
for (size_t i=0; i<sizeof(bits)*8; i++) {
......@@ -76,14 +76,14 @@ private:
}
}
Q_ASSERT(buttonCount != 0);
if (buttonCount > 1) {
Q_ASSERT(buttons & *defaultButton);
} else {
// Force default button to be set correctly for single button case to make unit test code simpler
*defaultButton = static_cast<QMessageBox::StandardButton>(static_cast<int>(buttons));
}
return (parent == NULL) ? MainWindow::instance() : parent;
}
......@@ -91,9 +91,9 @@ private:
{
// You can't use QGCMessageBox if QGCApplication is not created yet.
Q_ASSERT(qgcApp());
Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCMessageBox can only be called from main thread");
parent = _validateParameters(buttons, &defaultButton, parent);
if (MainWindow::instance()) {
......@@ -102,7 +102,7 @@ private:
parent = MainWindow::instance();
}
}
#ifdef QT_DEBUG
if (qgcApp()->runningUnitTests()) {
qDebug() << "QGCMessageBox (unit testing)" << title << text;
......@@ -115,6 +115,10 @@ private:
QMessageBox box(icon, emptyTitle, title, buttons, parent);
box.setDefaultButton(defaultButton);
box.setInformativeText(text);
// Get this thing off a proper size
QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
QGridLayout* layout = (QGridLayout*)box.layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
#else
QMessageBox box(icon, title, text, buttons, parent);
box.setDefaultButton(defaultButton);
......
......@@ -49,13 +49,13 @@ QColor QGCPalette::_button[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
};
QColor QGCPalette::_buttonText[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
{ QColor(0, 0, 0), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) },
{ QColor(0, 0, 0), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) },
{ QColor(0x2c, 0x2c, 0x2c), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) },
{ QColor(0x2c, 0x2c, 0x2c), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) },
};
QColor QGCPalette::_text[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
{ QColor(0, 0, 0), QColor(0, 0, 0), QColor(0, 0, 0) },
{ QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) }
{ QColor(0x58, 0x58, 0x58), QColor(0, 0, 0), QColor(0, 0, 0) },
{ QColor(0x58, 0x58, 0x58), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) }
};
QColor QGCPalette::_window[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
......@@ -64,8 +64,13 @@ QColor QGCPalette::_window[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
};
QColor QGCPalette::_windowText[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
{ QColor(0, 0, 0), QColor(0, 0, 0), QColor(0, 0, 0) },
{ QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) }
{ QColor(0x58, 0x58, 0x58), QColor(0, 0, 0), QColor(0, 0, 0) },
{ QColor(0x58, 0x58, 0x58), QColor(0xFF, 0xFF, 0xFF), QColor(0xFF, 0xFF, 0xFF) }
};
QColor QGCPalette::_buttonHighlight[QGCPalette::_cThemes][QGCPalette::_cColorGroups] = {
{ QColor(0x58, 0x58, 0x58), QColor(0xee, 0xe3, 0x33), QColor(0xee, 0xe3, 0x33) },
{ QColor(0x58, 0x58, 0x58), QColor(0xee, 0xe3, 0x33), QColor(0xee, 0xe3, 0x33) },
};
QGCPalette::QGCPalette(QObject* parent) :
......
......@@ -50,6 +50,9 @@ class QGCPalette : public QObject
Q_PROPERTY(QColor text READ text NOTIFY paletteChanged)
Q_PROPERTY(QColor window READ window NOTIFY paletteChanged)
Q_PROPERTY(QColor windowText READ windowText NOTIFY paletteChanged)
/// The buttonHighlight color identifies the button background color when hovered or selected.
Q_PROPERTY(QColor buttonHighlight READ buttonHighlight NOTIFY paletteChanged)
public:
enum ColorGroup {
......@@ -76,6 +79,7 @@ public:
QColor text(void) const { return _text[_theme][_colorGroup]; }
QColor window(void) const { return _window[_theme][_colorGroup]; }
QColor windowText(void) const { return _windowText[_theme][_colorGroup]; }
QColor buttonHighlight(void) const { return _buttonHighlight[_theme][_colorGroup]; }
static Theme globalTheme(void) { return _theme; }
static void setGlobalTheme(Theme newTheme);
......@@ -97,6 +101,7 @@ private:
static QColor _text[_cThemes][_cColorGroups];
static QColor _window[_cThemes][_cColorGroups];
static QColor _windowText[_cThemes][_cColorGroups];
static QColor _buttonHighlight[_cThemes][_cColorGroups];
void _themeChanged(void);
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
Button {
property var __qgcPal: QGCPalette { colorGroup: enabled ? QGCPalette.Active : QGCPalette.Disabled }
style: ButtonStyle {
background: Rectangle {
implicitWidth: 100
implicitHeight: 25
color: control.hovered ? control.__qgcPal.buttonHighlight : control.__qgcPal.button
}
label: Text {
width: parent.width
height: parent.height
verticalAlignment: TextEdit.AlignVCenter
horizontalAlignment: TextEdit.AlignHCenter
text: control.text
color: control.__qgcPal.buttonText
}
}
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
CheckBox {
property var __qgcPal: QGCPalette { colorGroup: enabled ? QGCPalette.Active : QGCPalette.Disabled }
style: CheckBoxStyle {
label: Item {
implicitWidth: text.implicitWidth + 2
implicitHeight: text.implicitHeight
baselineOffset: text.baselineOffset
Rectangle {
anchors.fill: text
anchors.margins: -1
anchors.leftMargin: -3
anchors.rightMargin: -3
visible: control.activeFocus
height: 6
radius: 3
color: "#224f9fef"
border.color: "#47b"
opacity: 0.6
}
Text {
id: text
text: control.text
anchors.centerIn: parent
color: control.__qgcPal.windowText
}
}
}
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
Text {
property var __palette: QGCPalette { colorGroup: enabled ? QGCPalette.Active : QGCPalette.Disabled }
property bool enabled: true
color: __palette.windowText
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
RadioButton {
property var __qgcPal: QGCPalette { colorGroup: enabled ? QGCPalette.Active : QGCPalette.Disabled }
style: RadioButtonStyle {
label: Item {
implicitWidth: text.implicitWidth + 2
implicitHeight: text.implicitHeight
baselineOffset: text.y + text.baselineOffset
Rectangle {
anchors.fill: text
anchors.margins: -1
anchors.leftMargin: -3
anchors.rightMargin: -3
visible: control.activeFocus
height: 6
radius: 3
color: "#224f9fef"
border.color: "#47b"
opacity: 0.6
}
Text {
id: text
text: control.text
anchors.centerIn: parent
color: control.__qgcPal.windowText
}
}
}
}
This diff is collapsed.
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "QmlTestWidget.h"
QmlTestWidget::QmlTestWidget(void)
{
setAttribute(Qt::WA_DeleteOnClose);
resize(500, 500);
setVisible(true);
setSource(QUrl::fromUserInput("qrc:qml/QmlTest.qml"));
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef QmlTestWidget_h
#define QmlTestWidget_h
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "QGCQmlWidgetHolder.h"
/// This is used to create widgets which are implemented in QML.
class QmlTestWidget : public QGCQmlWidgetHolder
{
Q_OBJECT
public:
QmlTestWidget(void);
};
#endif
......@@ -2,11 +2,12 @@ import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtGraphicalEffects 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
Button {
checkable: true
height: 80
height: 60
text: "Button"
property bool setupComplete: true
......@@ -21,7 +22,7 @@ Button {
background: Rectangle {
id: innerRect
readonly property real titleHeight: 30
readonly property real titleHeight: 20
border.color: control.checked ? "#eee333" : "#676767"
radius: 10
......@@ -44,7 +45,7 @@ Button {
Rectangle {
id: setupIndicator
readonly property real indicatorRadius: 6
readonly property real indicatorRadius: 4
x: parent.width - (indicatorRadius * 2) - 5
y: (parent.height - (indicatorRadius * 2)) / 2
......
Module QGroundControl.Controls
SetupButton 1.0 SetupButton.qml
QGCLabel 1.0 QGCLabel.qml
QGCButton 1.0 QGCButton.qml
QGCRadioButton 1.0 QGCRadioButton.qml
QGCCheckBox 1.0 QGCCheckBox.qml
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FirmwareUpgradeController 1.0
Rectangle {
width: 600
height: 600
property var qgcPal: QGCPalette { colorGroup: QGCPalette.Active }
property FirmwareUpgradeController controller: FirmwareUpgradeController {
upgradeButton: upgradeButton
statusLog: statusTextArea
firmwareType: FirmwareUpgradeController.StableFirmware
}
color: qgcPal.window
Column {
anchors.fill:parent
Text {
text: "FIRMWARE UPDATE"
color: qgcPal.windowText
font.pointSize: 20
}
Item {
// Just used as a spacer
height: 20
width: 10
}
ExclusiveGroup { id: firmwareGroup }
QGCRadioButton {
id: stableFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Standard Version (stable)")
checked: true
enabled: upgradeButton.enabled
onClicked: {
if (checked)
controller.firmwareType = FirmwareUpgradeController.StableFirmware
}
}
QGCRadioButton {
id: betaFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Beta Testing (beta)")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.BetaFirmware }
}
QGCRadioButton {
id: devloperFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Developer Build (master)")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.DeveloperFirmware }
}
QGCRadioButton {
id: customFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Custom firmware file...")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.CustomFirmware }
}
Item {
// Just used as a spacer
height: 20
width: 10
}
QGCButton {
id: upgradeButton
text: "UPGRADE"
onClicked: {
controller.doFirmwareUpgrade();
}
}
Item {
// Just used as a spacer
height: 20
width: 10
}
TextArea {
id: statusTextArea
width: parent.width
height: 300
readOnly: true
style: TextAreaStyle {
textColor: qgcPal.windowText
backgroundColor: qgcPal.window
}
}
}
}
......@@ -2,7 +2,7 @@
QGroundControl Open Source Ground Control Station
(c) 2009, 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
......@@ -22,43 +22,65 @@
======================================================================*/
/// @file
/// @brief PX4 Firmware Upgrade UI
/// @author Don Gagne <don@thegagnes.com>
#ifndef PX4FirmwareUpgrade_H
#define PX4FirmwareUpgrade_H
#ifndef FirmwareUpgradeController_H
#define FirmwareUpgradeController_H
#include <QWidget>
#include "PX4FirmwareUpgradeThread.h"
#include <QObject>
#include <QUrl>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPixmap>
#include <QQuickItem>
#include "qextserialport.h"
#include <stdint.h>
#include "PX4FirmwareUpgradeThread.h"
#include "ui_PX4FirmwareUpgrade.h"
namespace Ui {
class PX4RCCalibration;
}
class PX4FirmwareUpgrade : public QWidget
// Firmware Upgrade MVC Controller for FirmwareUpgrade.qml.
class FirmwareUpgradeController : public QObject
{
Q_OBJECT
public:
explicit PX4FirmwareUpgrade(QWidget *parent = 0);
~PX4FirmwareUpgrade();
FirmwareUpgradeController(void);
/// Supported firmware types
typedef enum {
StableFirmware,
BetaFirmware,
DeveloperFirmware,
CustomFirmware
} FirmwareType_t;
Q_ENUMS(FirmwareType_t)
/// Firmare type to load
Q_PROPERTY(FirmwareType_t firmwareType READ firmwareType WRITE setFirmwareType)
/// Upgrade push button in UI
Q_PROPERTY(QQuickItem* upgradeButton READ upgradeButton WRITE setUpgradeButton)
/// TextArea for log output
Q_PROPERTY(QQuickItem* statusLog READ statusLog WRITE setStatusLog)
/// Begins the firware upgrade process
Q_INVOKABLE void doFirmwareUpgrade(void);
FirmwareType_t firmwareType(void) { return _firmwareType; }
void setFirmwareType(FirmwareType_t firmwareType) { _firmwareType = firmwareType; }
QQuickItem* upgradeButton(void) { return _upgradeButton; }
void setUpgradeButton(QQuickItem* upgradeButton) { _upgradeButton = upgradeButton; }
QQuickItem* statusLog(void) { return _statusLog; }
void setStatusLog(QQuickItem* statusLog) { _statusLog = statusLog; }
private slots:
void _tryAgainButton(void);
void _cancelButton(void);
void _nextButton(void);
void _firmwareSelected(int index);
void _downloadProgress(qint64 curr, qint64 total);
void _downloadFinished(void);
void _downloadError(QNetworkReply::NetworkError code);
......@@ -73,56 +95,18 @@ private slots:
void _eraseProgressTick(void);
private:
/// @brief The various states that the upgrade process progresses through.
enum upgradeStates {
upgradeStateBegin,
upgradeStateBoardSearch,
upgradeStateBoardNotFound,
upgradeStateBootloaderSearch,
upgradeStateBootloaderNotFound,
upgradeStateBootloaderError,
upgradeStateFirmwareSelect,
upgradeStateFirmwareDownloading,
upgradeStateDownloadFailed,
upgradeStateErasing,
upgradeStateEraseError,
upgradeStateFlashing,
upgradeStateFlashError,
upgradeStateVerifying,
upgradeStateVerifyError,
upgradeStateBoardUpgraded,
upgradeStateMax
};
void _setupState(enum upgradeStates state);
void _updateIndicatorUI(void);
void _findBoard(void);
void _findBootloader(void);
void _cancel(void);
void _cancelFind(void);
void _getFirmwareFile(void);
void _setBoardIcon(int boardID);
void _setFirmwareCombo(int boardID);
void _downloadFirmware(void);
void _cancelDownload(void);
void _erase(void);
typedef void (PX4FirmwareUpgrade::*stateFunc)(void);
struct stateMachineEntry {
enum upgradeStates state; ///< State machine state, used to verify correctness of entry
stateFunc next; ///< Method to call when Next is clicked, NULL for Next not available
stateFunc cancel; ///< Method to call when Cancel is clicked, NULL for Cancel not available
stateFunc tryAgain; ///< Method to call when Try Again is clicked, NULL for Try Again not available
const char* msg; ///< Text message to display to user for this state
};
const struct stateMachineEntry* _getStateMachineEntry(enum upgradeStates state);
enum upgradeStates _upgradeState; ///< Current state of the upgrade state machines
void _appendStatusLog(const QString& text);
QString _portName;
QString _portDescription;
......@@ -154,7 +138,11 @@ private:
static const int _findBoardTimeoutMsec = 30000; ///< Amount of time for user to plug in USB
static const int _findBootloaderTimeoutMsec = 5000; ///< Amount time to look for bootloader
Ui::PX4FirmwareUpgrade* _ui;
FirmwareType_t _firmwareType; ///< Firmware type to load
QQuickItem* _upgradeButton; ///< Upgrade button in ui
QQuickItem* _statusLog; ///< Status log TextArea Qml control
bool _searchingForBoard; ///< true: searching for board, false: search for bootloader
};
#endif // PX4FirmwareUpgrade_H
#endif
......@@ -174,9 +174,13 @@ void PX4FirmwareUpgradeThreadWorker::timeout(void)
void PX4FirmwareUpgradeThreadWorker::sendBootloaderReboot(void)
{
_bootloader->sendBootloaderReboot(_bootloaderPort);
_bootloaderPort->deleteLater();
_bootloaderPort = NULL;
if (_bootloaderPort) {
if (_bootloaderPort->isOpen()) {
_bootloader->sendBootloaderReboot(_bootloaderPort);
}
_bootloaderPort->deleteLater();
_bootloaderPort = NULL;
}
}
void PX4FirmwareUpgradeThreadWorker::program(const QString firmwareFilename)
......
......@@ -30,11 +30,11 @@
#include "UASManager.h"
#include "AutoPilotPluginManager.h"
#include "VehicleComponent.h"
#include "PX4FirmwareUpgrade.h"
#include "ParameterEditor.h"
#include "QGCQmlWidgetHolder.h"
#include "MainWindow.h"
#include "QGCMessageBox.h"
#include "FirmwareUpgradeController.h"
#include <QQmlError>
#include <QQmlContext>
......@@ -54,25 +54,12 @@ SetupView::SetupView(QWidget* parent) :
Q_UNUSED(fSucceeded);
Q_ASSERT(fSucceeded);
//setResizeMode(SizeRootObjectToView);
_ui->buttonHolder->setAutoPilot(NULL);
_ui->buttonHolder->setSource(QUrl::fromUserInput("qrc:/qml/SetupViewButtons.qml"));
QObject* rootObject = (QObject*)_ui->buttonHolder->rootObject();
Q_ASSERT(rootObject);
fSucceeded = connect(rootObject, SIGNAL(setupButtonClicked(QVariant)), this, SLOT(_setupButtonClicked(QVariant)));
Q_ASSERT(fSucceeded);
fSucceeded = connect(rootObject, SIGNAL(firmwareButtonClicked()), this, SLOT(_firmwareButtonClicked()));
Q_ASSERT(fSucceeded);
fSucceeded = connect(rootObject, SIGNAL(parametersButtonClicked()), this, SLOT(_parametersButtonClicked()));
Q_ASSERT(fSucceeded);
_ui->buttonHolder->rootContext()->setContextProperty("controller", this);
fSucceeded = connect(rootObject, SIGNAL(summaryButtonClicked()), this, SLOT(_summaryButtonClicked()));
Q_ASSERT(fSucceeded);
qmlRegisterType<FirmwareUpgradeController>("QGroundControl.FirmwareUpgradeController", 1, 0, "FirmwareUpgradeController");
_setActiveUAS(UASManager::instance()->getActiveUAS());
}
......@@ -91,7 +78,7 @@ void SetupView::_setActiveUAS(UASInterface* uas)
_autoPilotPlugin = NULL;
_ui->buttonHolder->setAutoPilot(NULL);
_firmwareButtonClicked();
firmwareButtonClicked();
QObject* button = _ui->buttonHolder->rootObject()->findChild<QObject*>("firmwareButton");
Q_ASSERT(button);
button->setProperty("checked", true);
......@@ -111,7 +98,7 @@ void SetupView::_setActiveUAS(UASInterface* uas)
void SetupView::_pluginReady(void)
{
_ui->buttonHolder->setAutoPilot(_autoPilotPlugin);
_summaryButtonClicked();
summaryButtonClicked();
QObject* button = _ui->buttonHolder->rootObject()->findChild<QObject*>("summaryButton");
Q_ASSERT(button);
button->setProperty("checked", true);
......@@ -126,24 +113,28 @@ void SetupView::_changeSetupWidget(QWidget* newWidget)
_ui->setupWidgetLayout->addWidget(newWidget);
}
void SetupView::_firmwareButtonClicked(void)
void SetupView::firmwareButtonClicked(void)
{
if (_uasCurrent && _uasCurrent->isArmed()) {
QGCMessageBox::warning("Setup", "Firmware Update cannot be performed while vehicle is armed.");
return;
}
QGCQmlWidgetHolder* setup = new QGCQmlWidgetHolder;
Q_CHECK_PTR(setup);
PX4FirmwareUpgrade* setup = new PX4FirmwareUpgrade(this);
setup->setSource(QUrl::fromUserInput("qrc:/qml/FirmwareUpgrade.qml"));
_changeSetupWidget(setup);
}
void SetupView::_parametersButtonClicked(void)
void SetupView::parametersButtonClicked(void)
{
ParameterEditor* setup = new ParameterEditor(_uasCurrent, QStringList(), this);
_changeSetupWidget(setup);
}
void SetupView::_summaryButtonClicked(void)
void SetupView::summaryButtonClicked(void)
{
Q_ASSERT(_autoPilotPlugin);
......@@ -156,7 +147,7 @@ void SetupView::_summaryButtonClicked(void)
_changeSetupWidget(summary);
}
void SetupView::_setupButtonClicked(const QVariant& component)
void SetupView::setupButtonClicked(const QVariant& component)
{
if (_uasCurrent->isArmed()) {
QGCMessageBox::warning("Setup", "Setup cannot be performed while vehicle is armed.");
......
......@@ -47,13 +47,14 @@ public:
explicit SetupView(QWidget* parent = 0);
~SetupView();
Q_INVOKABLE void firmwareButtonClicked(void);
Q_INVOKABLE void parametersButtonClicked(void);
Q_INVOKABLE void summaryButtonClicked(void);
Q_INVOKABLE void setupButtonClicked(const QVariant& component);
private slots:
void _setActiveUAS(UASInterface* uas);
void _pluginReady(void);
void _firmwareButtonClicked(void);
void _parametersButtonClicked(void);
void _summaryButtonClicked(void);
void _setupButtonClicked(const QVariant& component);
private:
void _changeSetupWidget(QWidget* newWidget);
......
......@@ -24,13 +24,13 @@
</property>
<property name="minimumSize">
<size>
<width>160</width>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>160</width>
<width>120</width>
<height>16777215</height>
</size>
</property>
......
......@@ -2,6 +2,9 @@ import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QtGraphicalEffects 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
Rectangle {
......@@ -10,17 +13,14 @@ Rectangle {
QGCPalette { id: palette; colorGroup: QGCPalette.Active }
color: palette.window
signal firmwareButtonClicked;
signal summaryButtonClicked;
signal parametersButtonClicked;
signal setupButtonClicked(variant component);
ExclusiveGroup { id: setupButtonGroup }
Component {
id: disconnectedButtons
Column {
anchors.fill: parent
spacing: 10
SetupButton {
......@@ -29,7 +29,7 @@ Rectangle {
text: "FIRMWARE"
setupIndicator: false
exclusiveGroup: setupButtonGroup
onClicked: topLevel.firmwareButtonClicked()
onClicked: controller.firmwareButtonClicked()
}
}
}
......@@ -38,15 +38,17 @@ Rectangle {
id: connectedButtons
Column {
anchors.fill: parent
spacing: 10
SetupButton {
id: summaryButton; objectName: "summaryButton"
width: parent.width
text: "VEHICLE SUMMARY"
text: "SUMMARY"
setupIndicator: false
exclusiveGroup: setupButtonGroup
onClicked: topLevel.summaryButtonClicked()
onClicked: controller.summaryButtonClicked()
}
SetupButton {
......@@ -55,7 +57,7 @@ Rectangle {
text: "FIRMWARE"
setupIndicator: false
exclusiveGroup: setupButtonGroup
onClicked: topLevel.firmwareButtonClicked()
onClicked: controller.firmwareButtonClicked()
}
Repeater {
......@@ -66,7 +68,7 @@ Rectangle {
text: modelData.name.toUpperCase()
setupComplete: modelData.setupComplete
exclusiveGroup: setupButtonGroup
onClicked: topLevel.setupButtonClicked(modelData)
onClicked: controller.setupButtonClicked(modelData)
}
}
......@@ -75,7 +77,7 @@ Rectangle {
text: "PARAMETERS"
setupIndicator: false
exclusiveGroup: setupButtonGroup
onClicked: topLevel.parametersButtonClicked()
onClicked: controller.parametersButtonClicked()
}
}
}
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "SetupViewTest.h"
#include "MockLink.h"
#include "QGCMessageBox.h"
UT_REGISTER_TEST(SetupViewTest)
SetupViewTest::SetupViewTest(void)
{
}
void SetupViewTest::init(void)
{
UnitTest::init();
_mainWindow = MainWindow::_create(NULL);
Q_CHECK_PTR(_mainWindow);
}
void SetupViewTest::cleanup(void)
{
_mainWindow->close();
delete _mainWindow;
UnitTest::cleanup();
}
void SetupViewTest::_clickThrough_test(void)
{
LinkManager* linkMgr = LinkManager::instance();
Q_CHECK_PTR(linkMgr);
MockLink* link = new MockLink();
Q_CHECK_PTR(link);
link->setAutopilotType(MAV_AUTOPILOT_PX4);
LinkManager::instance()->addLink(link);
linkMgr->connectLink(link);
QTest::qWait(5000); // Give enough time for UI to settle and heartbeats to go through
// Find the Setup button and click it
QGCToolBar* toolbar = _mainWindow->findChild<QGCToolBar*>();
Q_ASSERT(toolbar);
QList<QToolButton*> buttons = toolbar->findChildren<QToolButton*>();
QToolButton* setupButton = NULL;
foreach(QToolButton* button, buttons) {
if (button->text() == "Setup") {
setupButton = button;
break;
}
}
Q_ASSERT(setupButton);
QTest::mouseClick(setupButton, Qt::LeftButton);
QTest::qWait(1000);
// Click through all the setup buttons
// FIXME: NYI
// On MainWindow close we should get a message box telling the user to disconnect first. Disconnect will then pop
// the log file save dialog.
setExpectedMessageBox(QGCMessageBox::Yes);
setExpectedFileDialog(getSaveFileName, QStringList());
_mainWindow->close();
QTest::qWait(1000); // Need to allow signals to move between threads
checkExpectedMessageBox();
checkExpectedFileDialog();
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef SetupViewTest_H
#define SetupViewTest_H
#include "UnitTest.h"
#include "MainWindow.h"
/// Click through test for Setup View buttons
class SetupViewTest : public UnitTest
{
Q_OBJECT
public:
SetupViewTest(void);
private slots:
void init(void);
void cleanup(void);
void _clickThrough_test(void);
private:
MainWindow* _mainWindow;
};
#endif
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
Rectangle {
width: 600
......
......@@ -21,86 +21,97 @@ This file is part of the QGROUNDCONTROL project
======================================================================*/
/**
* @file
* @brief Definition of class CommConfigurationWindow
*
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#ifndef _COMMCONFIGURATIONWINDOW_H_
#define _COMMCONFIGURATIONWINDOW_H_
#include <QObject>
#include <QDialog>
#include <QAction>
#include "LinkInterface.h"
#include "ProtocolInterface.h"
#include "ui_CommSettings.h"
enum qgc_link_t {
QGC_LINK_SERIAL,
QGC_LINK_UDP,
QGC_LINK_TCP,
QGC_LINK_SIMULATION,
QGC_LINK_FORWARDING,
#ifdef UNITTEST_BUILD
QGC_LINK_MOCK,
#endif
#ifdef QGC_XBEE_ENABLED
QGC_LINK_XBEE,
#endif
#ifdef QGC_RTLAB_ENABLED
QGC_LINK_OPAL
#endif
};
enum qgc_protocol_t {
QGC_PROTOCOL_MAVLINK,
};
/*!
@file
@brief Link specific configuration base class
@author Gus Grubba <mavlink@grubba.com>
*/
#include "LinkConfiguration.h"
#include "SerialLink.h"
#include "UDPLink.h"
#ifdef QGC_RTLAB_ENABLED
#include "OpalLink.h"
#ifdef UNITTEST_BUILD
#include "MockLink.h"
#endif
/**
* @brief Configuration window for communication links
*/
class CommConfigurationWindow : public QDialog
{
Q_OBJECT
public:
CommConfigurationWindow(LinkInterface* link, QWidget *parent = 0);
~CommConfigurationWindow();
QAction* getAction();
void setLinkType(qgc_link_t linktype);
private slots:
void linkCurrentIndexChanged(int currentIndex);
public slots:
/** @brief Set the protocol for this link */
void setProtocol(int protocol);
void setConnection();
void setLinkName(QString name);
/** @brief Disconnects the associated link, removes it from all menus and closes the window. */
void remove();
#define LINK_SETTING_ROOT "LinkConfigurations"
private slots:
void _linkConnected(void);
void _linkDisconnected(void);
private:
void _connectionState(bool connect);
Ui::commSettings ui;
LinkInterface* link;
QAction* action;
};
LinkConfiguration::LinkConfiguration(const QString& name)
: _preferred(false)
{
_link = NULL;
_name = name;
Q_ASSERT(!_name.isEmpty());
}
LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
{
_link = copy->getLink();
_name = copy->name();
_preferred = copy->isPreferred();
Q_ASSERT(!_name.isEmpty());
}
#endif // _COMMCONFIGURATIONWINDOW_H_
void LinkConfiguration::copyFrom(LinkConfiguration* source)
{
Q_ASSERT(source != NULL);
_link = source->getLink();
_name = source->name();
_preferred = source->isPreferred();
}
/*!
Where the settings are saved
@return The root path of the setting.
*/
const QString LinkConfiguration::settingsRoot()
{
return QString(LINK_SETTING_ROOT);
}
/*!
Configuration Factory
@return A new instance of the given type
*/
LinkConfiguration* LinkConfiguration::createSettings(int type, const QString& name)
{
LinkConfiguration* config = NULL;
switch(type) {
case LinkConfiguration::TypeSerial:
config = new SerialConfiguration(name);
break;
case LinkConfiguration::TypeUdp:
config = new UDPConfiguration(name);
break;
#ifdef UNITTEST_BUILD
case LinkConfiguration::TypeMock:
config = new MockConfiguration(name);
break;
#endif
}
return config;
}
/*!
Duplicate link settings
@return A new copy of the given settings instance
*/
LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* source)
{
LinkConfiguration* dupe = NULL;
switch(source->type()) {
case TypeSerial:
dupe = new SerialConfiguration(dynamic_cast<SerialConfiguration*>(source));
break;
case TypeUdp:
dupe = new UDPConfiguration(dynamic_cast<UDPConfiguration*>(source));
break;
#ifdef UNITTEST_BUILD
case TypeMock:
dupe = new MockConfiguration(dynamic_cast<MockConfiguration*>(source));
break;
#endif
}
return dupe;
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef LINKCONFIGURATION_H
#define LINKCONFIGURATION_H
#include <QSettings>
class LinkInterface;
/// Interface holding link specific settings.
class LinkConfiguration
{
public:
LinkConfiguration(const QString& name);
LinkConfiguration(LinkConfiguration* copy);
virtual ~LinkConfiguration() {}
/// The link types supported by QGC
enum {
TypeSerial, ///< Serial Link
TypeUdp, ///< UDP Link
// TODO Below is not yet implemented
#if 0
TypeTcp, ///< TCP Link
TypeSimulation, ///< Simulation Link
TypeForwarding, ///< Forwarding Link
TypeXbee, ///< XBee Proprietary Link
TypeOpal, ///< Opal-RT Link
#endif
#ifdef UNITTEST_BUILD
TypeMock, ///< Mock Link for Unitesting
#endif
TypeLast // Last type value (type >= TypeLast == invalid)
};
/*!
* @brief Get configuration name
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @return The name of this link.
*/
const QString name() { return _name; }
/*!
* @brief Set the name of this link configuration.
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @param[in] name The configuration name
*/
void setName(const QString name) {_name = name; }
/*!
* @brief Set the link this configuration is currently attched to.
*
* @param[in] link The pointer to the current LinkInterface instance (if any)
*/
void setLink(LinkInterface* link) { _link = link; }
/*!
* @brief Get the link this configuration is currently attched to.
*
* @return The pointer to the current LinkInterface instance (if any)
*/
LinkInterface* getLink() { return _link; }
/*!
*
* Is this a preferred configuration? (decided at runtime)
* @return True if this is a known configuration (PX4, etc.)
*/
bool isPreferred() { return _preferred; }
/*!
* Set if this is this a preferred configuration. (decided at runtime)
*/
void setPreferred(bool preferred = true) { _preferred = preferred; }
/// Virtual Methods
/*!
* @brief Connection type
*
* Pure virtual method returning one of the -TypeXxx types above.
* @return The type of links these settings belong to.
*/
virtual int type() = 0;
/*!
* @brief Load settings
*
* Pure virtual method telling the instance to load its configuration.
* @param[in] settings The QSettings instance to use
* @param[in] root The root path of the setting.
*/
virtual void loadSettings(QSettings& settings, const QString& root) = 0;
/*!
* @brief Save settings
*
* Pure virtual method telling the instance to save its configuration.
* @param[in] settings The QSettings instance to use
* @param[in] root The root path of the setting.
*/
virtual void saveSettings(QSettings& settings, const QString& root) = 0;
/*!
* @brief Update settings
*
* After editing the settings, use this method to tell the connected link (if any) to reload its configuration.
*/
virtual void updateSettings() {}
/*!
* @brief Copy instance data
*
* When manipulating data, you create a copy of the configuration using the copy constructor,
* edit it and then transfer its content to the original using this method.
* @param[in] source The source instance (the edited copy)
*/
virtual void copyFrom(LinkConfiguration* source);
/// Helper static methods
/*!
* @brief Root path for QSettings
*
* @return The root path of the settings.
*/
static const QString settingsRoot();
/*!
* @brief Create new link configuration instance
*
* Configuration Factory. Creates an appropriate configuration instance based on the given type.
* @return A new instance of the given type
*/
static LinkConfiguration* createSettings(int type, const QString& name);
/*!
* @brief Duplicate configuration instance
*
* Helper method to create a new instance copy for editing.
* @return A new copy of the given settings instance
*/
static LinkConfiguration* duplicateSettings(LinkConfiguration *source);
protected:
LinkInterface* _link; ///< Link currently using this configuration (if any)
private:
QString _name;
bool _preferred; ///< Determined internally if this is a preferred connection. It comes up first in the drop down box.
};
#endif // LINKCONFIGURATION_H
......@@ -39,6 +39,7 @@ along with PIXHAWK. If not, see <http://www.gnu.org/licenses/>.
#include <QMetaType>
class LinkManager;
class LinkConfiguration;
/**
* The link interface defines the interface for all links used to communicate
......@@ -48,10 +49,10 @@ class LinkManager;
class LinkInterface : public QThread
{
Q_OBJECT
// Only LinkManager is allowed to _connect, _disconnect or delete a link
friend class LinkManager;
public:
LinkInterface() :
QThread(0),
......@@ -59,27 +60,33 @@ public:
_deletedByLinkManager(false)
{
// Initialize everything for the data rate calculation buffers.
inDataIndex = 0;
inDataIndex = 0;
outDataIndex = 0;
// Initialize our data rate buffers manually, cause C++<03 is dumb.
for (int i = 0; i < dataRateBufferSize; ++i)
{
inDataWriteAmounts[i] = 0;
inDataWriteTimes[i] = 0;
outDataWriteAmounts[i] = 0;
outDataWriteTimes[i] = 0;
}
// Initialize our data rate buffers.
memset(inDataWriteAmounts, 0, sizeof(inDataWriteAmounts));
memset(inDataWriteTimes, 0, sizeof(inDataWriteTimes));
memset(outDataWriteAmounts,0, sizeof(outDataWriteAmounts));
memset(outDataWriteTimes, 0, sizeof(outDataWriteTimes));
qRegisterMetaType<LinkInterface*>("LinkInterface*");
}
/**
* @brief Destructor
* LinkManager take ownership of Links once they are added to it. Once added to LinkManager
* use LinkManager::deleteLink to remove if necessary.
**/
virtual ~LinkInterface() {
// LinkManager take ownership of Links once they are added to it. Once added to LinkManager
// user LinkManager::deleteLink to remove if necessary/
Q_ASSERT(!_ownedByLinkManager || _deletedByLinkManager);
}
/**
* @brief Get link configuration (if used)
* @return A pointer to the instance of LinkConfiguration if supported. NULL otherwise.
**/
virtual LinkConfiguration* getLinkConfiguration() { return NULL; }
/* Connection management */
/**
......@@ -142,7 +149,7 @@ public:
{
return getCurrentDataRate(outDataIndex, outDataWriteTimes, outDataWriteAmounts);
}
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
......@@ -323,14 +330,14 @@ private:
* @return True if connection could be established, false otherwise
**/
virtual bool _connect(void) = 0;
/**
* @brief Disconnect this interface logically
*
* @return True if connection could be terminated, false otherwise
**/
virtual bool _disconnect(void) = 0;
bool _ownedByLinkManager; ///< true: This link has been added to LinkManager, false: Link not added to LinkManager
bool _deletedByLinkManager; ///< true: Link being deleted from LinkManager, false: error, Links should only be deleted from LinkManager
};
......
This diff is collapsed.
......@@ -31,8 +31,17 @@ This file is part of the PIXHAWK project
#include <QMultiMap>
#include <QMutex>
#include "LinkConfiguration.h"
#include "LinkInterface.h"
// Links
#include "SerialLink.h"
#include "UDPLink.h"
#ifdef UNITTEST_BUILD
#include "MockLink.h"
#endif
#include "ProtocolInterface.h"
#include "QGCSingleton.h"
#include "MAVLinkProtocol.h"
......@@ -48,14 +57,38 @@ class LinkManagerTest;
class LinkManager : public QGCSingleton
{
Q_OBJECT
DECLARE_QGC_SINGLETON(LinkManager, LinkManager)
/// Unit Test has access to private constructor/destructor
friend class LinkManagerTest;
public:
/*!
Add a new link configuration setting to the list
@param[in] link An instance of the link setting.
*/
void addLinkConfiguration(LinkConfiguration* link);
/*!
Removes (and deletes) an existing link configuration setting from the list
@param[in] link An instance of the link setting.
*/
void removeLinkConfiguration(LinkConfiguration* link);
/// Load list of link configurations from disk
void loadLinkConfigurationList();
/// Save list of link configurations from disk
void saveLinkConfigurationList();
/// Get a list of the configured links. This is the list of configured links that can be used by QGC.
const QList<LinkConfiguration*> getLinkConfigurationList();
/// Suspend automatic confguration updates (during link maintenance for instance)
void suspendConfigurationUpdates(bool suspend);
/// Returns list of all links
const QList<LinkInterface*> getLinks();
......@@ -65,53 +98,69 @@ public:
/// Sets the flag to suspend the all new connections
/// @param reason User visible reason to suspend connections
void setConnectionsSuspended(QString reason);
/// Sets the flag to allow new connections to be made
void setConnectionsAllowed(void) { _connectionsSuspended = false; }
/// Creates (and adds) a link based on the given configuration instance. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
LinkInterface* createLink(LinkConfiguration* config);
/// Creates (and adds) a link based on the given configuration name. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
LinkInterface* createLink(const QString& name);
/// Adds the link to the LinkManager. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
void addLink(LinkInterface* link);
/// Deletes the specified link. Will disconnect if connected.
// TODO Will also crash if called. MAVLink protocol is not handling the disconnect properly.
void deleteLink(LinkInterface* link);
/// Re-connects all existing links
bool connectAll();
/// Disconnects all existing links
bool disconnectAll();
/// Connect the specified link
bool connectLink(LinkInterface* link);
/// Disconnect the specified link
bool disconnectLink(LinkInterface* link);
signals:
void newLink(LinkInterface* link);
void linkDeleted(LinkInterface* link);
void linkConnected(LinkInterface* link);
void linkDisconnected(LinkInterface* link);
void linkConfigurationChanged();
private slots:
void _linkConnected(void);
void _linkDisconnected(void);
private:
/// All access to LinkManager is through LinkManager::instance
LinkManager(QObject* parent = NULL);
~LinkManager();
virtual void _shutdown(void);
bool _connectionsSuspendedMsg(void);
QList<LinkInterface*> _links; ///< List of available links
QMutex _linkListMutex; ///< Mutex for thread safe access to _links list
bool _connectionsSuspended; ///< true: all new connections should not be allowed
QString _connectionsSuspendedReason; ///< User visible reason for suspension
void _updateConfigurationList(void);
SerialConfiguration* _findSerialConfiguration(const QString& portName);
QList<LinkConfiguration*> _linkConfigurations; ///< List of configured links
QList<LinkInterface*> _links; ///< List of available links
QMutex _linkListMutex; ///< Mutex for thread safe access to _links list
bool _configUpdateSuspended; ///< true: stop updating configuration list
bool _configurationsLoaded; ///< true: Link configurations have been loaded
bool _connectionsSuspended; ///< true: all new connections should not be allowed
QString _connectionsSuspendedReason; ///< User visible reason for suspension
QTimer _portListTimer;
};
#endif
This diff is collapsed.
......@@ -32,18 +32,65 @@ This file is part of the QGROUNDCONTROL project
#ifndef SERIALLINK_H
#define SERIALLINK_H
class LinkInterface;
class SerialConfiguration;
class SerialLink;
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QString>
#include "QGCConfig.h"
#include "SerialLinkInterface.h"
// We use QSerialPort::SerialPortError in a signal so we must declare it as a meta type
#include <QSerialPort>
#include <QMetaType>
// We use QSerialPort::SerialPortError in a signal so we must declare it as a meta type
Q_DECLARE_METATYPE(QSerialPort::SerialPortError)
#include "QGCConfig.h"
#include "LinkManager.h"
class SerialConfiguration : public LinkConfiguration
{
public:
SerialConfiguration(const QString& name);
SerialConfiguration(SerialConfiguration* copy);
int baud() { return _baud; }
int dataBits() { return _dataBits; }
int flowControl() { return _flowControl; } ///< QSerialPort Enums
int stopBits() { return _stopBits; }
int parity() { return _parity; } ///< QSerialPort Enums
const QString portName() { return _portName; }
void setBaud (int baud);
void setDataBits (int databits);
void setFlowControl (int flowControl); ///< QSerialPort Enums
void setStopBits (int stopBits);
void setParity (int parity); ///< QSerialPort Enums
void setPortName (const QString& portName);
/// From LinkConfiguration
int type() { return LinkConfiguration::TypeSerial; }
void copyFrom(LinkConfiguration* source);
void loadSettings(QSettings& settings, const QString& root);
void saveSettings(QSettings& settings, const QString& root);
void updateSettings();
/*! @brief Get a list of the currently available ports */
static QList<QString> getCurrentPorts();
private:
int _baud;
int _dataBits;
int _flowControl;
int _stopBits;
int _parity;
QString _portName;
};
/**
* @brief The SerialLink class provides cross-platform access to serial links.
* It takes care of the link management and provides a common API to higher
......@@ -52,89 +99,36 @@ Q_DECLARE_METATYPE(QSerialPort::SerialPortError)
* safe.
*
*/
class SerialLink : public SerialLinkInterface
class SerialLink : public LinkInterface
{
Q_OBJECT
//Q_INTERFACES(SerialLinkInterface:LinkInterface)
friend class SerialConfiguration;
public:
SerialLink(QString portname = "",
int baudrate=57600,
bool flow=false,
bool parity=false,
int dataBits=8,
int stopBits=1);
~SerialLink();
static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in QGCConfig.h
/** @brief Get a list of the currently available ports */
QList<QString> getCurrentPorts();
/** @brief Check if the current port is a bootloader */
bool isBootloader();
void requestReset();
SerialLink(SerialConfiguration* config);
~SerialLink();
bool isConnected() const;
// LinkInterface
/**
* @brief The port handle
*/
QString getPortName() const;
/**
* @brief The human readable port name
*/
LinkConfiguration* getLinkConfiguration();
int getId() const;
QString getName() const;
int getBaudRate() const;
int getDataBits() const;
int getStopBits() const;
// ENUM values
int getBaudRateType() const;
int getFlowType() const;
int getParityType() const;
int getDataBitsType() const;
int getStopBitsType() const;
qint64 getConnectionSpeed() const;
qint64 getCurrentInDataRate() const;
qint64 getCurrentOutDataRate() const;
void loadSettings();
void writeSettings();
void checkIfCDC();
void requestReset();
bool isConnected() const;
qint64 getConnectionSpeed() const;
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
bool disconnect(void);
void run();
void run2();
int getId() const;
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
bool disconnect(void);
static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in QGCConfig.h
signals: //[TODO] Refactor to Linkinterface
void updateLink(LinkInterface*);
public slots:
bool setPortName(QString portName);
bool setBaudRate(int rate);
bool setDataBits(int dataBits);
bool setStopBits(int stopBits);
// Set string rate
bool setBaudRateString(const QString& rate);
// Set ENUM values
bool setBaudRateType(int rateIndex);
bool setFlowType(int flow);
bool setParityType(int parity);
bool setDataBitsType(int dataBits);
bool setStopBitsType(int stopBits);
void readBytes();
/**
......@@ -148,37 +142,34 @@ public slots:
void linkError(QSerialPort::SerialPortError error);
protected:
quint64 m_bytesRead;
QSerialPort* m_port;
int m_baud;
int m_dataBits;
int m_flowControl;
int m_stopBits;
int m_parity;
QString m_portName;
int m_timeout;
int m_id;
QMutex m_dataMutex; // Mutex for reading data from m_port
QMutex m_writeMutex; // Mutex for accessing the m_transmitBuffer.
QString type;
bool m_is_cdc;
QSerialPort* _port;
quint64 _bytesRead;
int _timeout;
int _id;
QMutex _dataMutex; // Mutex for reading data from _port
QMutex _writeMutex; // Mutex for accessing the _transmitBuffer.
QString _type;
private slots:
void _rerouteDisconnected(void);
private:
// From LinkInterface
virtual bool _connect(void);
virtual bool _disconnect(void);
void _emitLinkError(const QString& errorMsg);
bool _connect(void);
bool _disconnect(void);
volatile bool m_stopp;
volatile bool m_reqReset;
QMutex m_stoppMutex; // Mutex for accessing m_stopp
QByteArray m_transmitBuffer; // An internal buffer for receiving data from member functions and actually transmitting them via the serial port.
bool hardwareConnect(QString &type);
// Internal methods
void _emitLinkError(const QString& errorMsg);
bool _hardwareConnect(QString &_type);
bool _isBootloader();
void _resetConfiguration();
// Local data
volatile bool _stopp;
volatile bool _reqReset;
QMutex _stoppMutex; // Mutex for accessing _stopp
QByteArray _transmitBuffer; // An internal buffer for receiving data from member functions and actually transmitting them via the serial port.
SerialConfiguration* _config;
signals:
void aboutToCloseFlag();
......
......@@ -37,12 +37,12 @@ This file is part of the QGROUNDCONTROL project
#include <QVector>
#include <LinkInterface.h>
/*
class SerialLinkInterface : public LinkInterface
{
Q_OBJECT
public:
virtual QList<QString> getCurrentPorts() = 0;
virtual QString getPortName() const = 0;
virtual int getBaudRate() const = 0;
virtual int getDataBits() const = 0;
......@@ -66,7 +66,7 @@ public slots:
virtual void writeSettings() = 0;
};
*/
/* Declare C++ interface as Qt interface */
//Q_DECLARE_INTERFACE(SerialLinkInterface, "org.openground.comm.links.SerialLinkInterface/1.0")
......
This diff is collapsed.
......@@ -21,7 +21,7 @@ This file is part of the QGROUNDCONTROL project
======================================================================*/
/**
/*!
* @file
* @brief UDP connection (server) for unmanned vehicles
* @author Lorenz Meier <mavteam@student.ethz.ch>
......@@ -36,39 +36,120 @@ This file is part of the QGROUNDCONTROL project
#include <QMap>
#include <QMutex>
#include <QUdpSocket>
#include <LinkInterface.h>
#include "QGCConfig.h"
#include "LinkManager.h"
#define QGC_UDP_PORT 14550
class UDPConfiguration : public LinkConfiguration
{
public:
/*!
* @brief Regular constructor
*
* @param[in] name Configuration (user friendly) name
*/
UDPConfiguration(const QString& name);
/*!
* @brief Copy contructor
*
* When manipulating data, you create a copy of the configuration, edit it
* and then transfer its content to the original (using copyFrom() below). Use this
* contructor to create an editable copy.
*
* @param[in] source Original configuration
*/
UDPConfiguration(UDPConfiguration* source);
/*!
* @brief Begin iteration through the list of target hosts
*
* @param[out] host Host name
* @param[out] port Port number
* @return Returns false if list is empty
*/
bool firstHost (QString& host, int& port);
/*!
* @brief Continues iteration through the list of target hosts
*
* @param[out] host Host name
* @param[out] port Port number
* @return Returns false if reached the end of the list (in which case, both host and port are unchanged)
*/
bool nextHost (QString& host, int& port);
/*!
* @brief Get the number of target hosts
*
* @return Number of hosts in list
*/
int hostCount () { return _hosts.count(); }
/*!
* @brief The UDP port we bind to
*
* @return Port number
*/
quint16 localPort () { return _localPort; }
/*!
* @brief Add a target host
*
* @param[in] host Host name in standard formatt, e.g. localhost:14551 or 192.168.1.1:14551
*/
void addHost (const QString& host);
/*!
* @brief Add a target host
*
* @param[in] host Host name, e.g. localhost or 192.168.1.1
* @param[in] port Port number
*/
void addHost (const QString& host, int port);
/*!
* @brief Remove a target host from the list
*
* @param[in] host Host name, e.g. localhost or 192.168.1.1
*/
void removeHost (const QString& host);
/*!
* @brief Set the UDP port we bind to
*
* @param[in] port Port number
*/
void setLocalPort (quint16 port);
/// From LinkConfiguration
int type() { return LinkConfiguration::TypeUdp; }
void copyFrom(LinkConfiguration* source);
void loadSettings(QSettings& settings, const QString& root);
void saveSettings(QSettings& settings, const QString& root);
void updateSettings();
private:
QMutex _confMutex;
QMap<QString, int>::iterator _it;
QMap<QString, int> _hosts; ///< ("host", port)
quint16 _localPort;
};
class UDPLink : public LinkInterface
{
Q_OBJECT
//Q_INTERFACES(UDPLinkInterface:LinkInterface)
friend class UDPConfiguration;
public:
UDPLink(QHostAddress host = QHostAddress::Any, quint16 port = 14550);
//UDPLink(QHostAddress host = "239.255.76.67", quint16 port = 7667);
UDPLink(UDPConfiguration* config);
~UDPLink();
void requestReset() { }
bool isConnected() const;
int getPort() const {
return port;
}
/**
* @brief The human readable port name
*/
QString getName() const;
int getBaudRate() const;
int getBaudRateType() const;
int getFlowType() const;
int getParityType() const;
int getDataBitsType() const;
int getStopBitsType() const;
QList<QHostAddress> getHosts() const {
return hosts;
}
// Extensive statistics for scientific purposes
qint64 getConnectionSpeed() const;
......@@ -76,25 +157,25 @@ public:
qint64 getCurrentOutDataRate() const;
void run();
int getId() const;
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
bool disconnect(void);
LinkConfiguration* getLinkConfiguration() { return _config; }
public slots:
void setAddress(QHostAddress host);
void setPort(int port);
/** @brief Add a new host to broadcast messages to */
void addHost(const QString& host);
/** @brief Remove a host from broadcasting messages to */
void removeHost(const QString& host);
// void readPendingDatagrams();
/*! @brief Add a new host to broadcast messages to */
void addHost (const QString& host);
/*! @brief Remove a host from broadcasting messages to */
void removeHost (const QString& host);
void readBytes();
/**
/*!
* @brief Write a number of bytes to the interface.
*
* @param data Pointer to the data byte array
......@@ -103,25 +184,19 @@ public slots:
void writeBytes(const char* data, qint64 length);
protected:
QString name;
QHostAddress host;
quint16 port;
int id;
QUdpSocket* socket;
bool connectState;
QList<QHostAddress> hosts;
QList<quint16> ports;
QMutex dataMutex;
void setName(QString name);
QUdpSocket* _socket;
UDPConfiguration* _config;
bool _connectState;
int _id;
private:
// From LinkInterface
virtual bool _connect(void);
virtual bool _disconnect(void);
bool hardwareConnect(void);
bool _hardwareConnect();
void _restartConnection();
signals:
//Signals are defined by LinkInterface
......
......@@ -34,8 +34,6 @@ This file is part of the QGROUNDCONTROL project
#include "QGCApplication.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "UnitTest.h"
#include "CmdLineOptParser.h"
......@@ -67,7 +65,7 @@ void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
Q_UNUSED(reportType);
std::cerr << message << std::endl; // Output message to stderr
*returnValue = 0; // Don't break into debugger
return true; // We handled this fully ourselves
......@@ -103,23 +101,23 @@ int main(int argc, char *argv[])
// anyway to silence the debug output.
qRegisterMetaType<QSerialPort::SerialPortError>();
qRegisterMetaType<QAbstractSocket::SocketError>();
bool runUnitTests = false; // Run unit tests
#ifdef QT_DEBUG
// We parse a small set of command line options here prior to QGCApplication in order to handle the ones
// which need to be handled before a QApplication object is started.
bool quietWindowsAsserts = false; // Don't let asserts pop dialog boxes
CmdLineOpt_t rgCmdLineOptions[] = {
{ "--unittest", &runUnitTests, QString() },
{ "--no-windows-assert-ui", &quietWindowsAsserts, QString() },
// Add additional command line option flags here
};
ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false);
if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
_CrtSetReportHook(WindowsCrtReportHook);
......@@ -135,27 +133,27 @@ int main(int argc, char *argv[])
}
#endif
#endif // QT_DEBUG
QGCApplication* app = new QGCApplication(argc, argv, runUnitTests);
Q_CHECK_PTR(app);
// There appears to be a threading issue in qRegisterMetaType which can cause it to throw a qWarning
// about duplicate type converters. This is caused by a race condition in the Qt code. Still working
// with them on tracking down the bug. For now we register the type which is giving us problems here
// while we only have the main thread. That should prevent it from hitting the race condition later
// on in the code.
qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
app->_initCommon();
int exitCode;
#ifdef QT_DEBUG
if (runUnitTests) {
if (!app->_initForUnitTests()) {
return -1;
}
// Run the test
int failures = UnitTest::run(rgCmdLineOptions[0].optionArg);
if (failures == 0) {
......@@ -172,10 +170,10 @@ int main(int argc, char *argv[])
}
exitCode = app->exec();
}
delete app;
qDebug() << "After app delete";
return exitCode;
}
......@@ -54,21 +54,6 @@ void MainWindowTest::cleanup(void)
UnitTest::cleanup();
}
void MainWindowTest::_clickThrough_test(void)
{
QGCToolBar* toolbar = _mainWindow->findChild<QGCToolBar*>();
Q_ASSERT(toolbar);
QList<QToolButton*> buttons = toolbar->findChildren<QToolButton*>();
foreach(QToolButton* button, buttons) {
if (!button->menu()) {
QTest::mouseClick(button, Qt::LeftButton);
QTest::qWait(1000);
}
}
}
void MainWindowTest::_connectWindowClose_test(MAV_AUTOPILOT autopilot)
{
LinkManager* linkMgr = LinkManager::instance();
......@@ -81,6 +66,18 @@ void MainWindowTest::_connectWindowClose_test(MAV_AUTOPILOT autopilot)
linkMgr->connectLink(link);
QTest::qWait(5000); // Give enough time for UI to settle and heartbeats to go through
// Click through all top level toolbar buttons
QGCToolBar* toolbar = _mainWindow->findChild<QGCToolBar*>();
Q_ASSERT(toolbar);
QList<QToolButton*> buttons = toolbar->findChildren<QToolButton*>();
foreach(QToolButton* button, buttons) {
if (!button->menu()) {
QTest::mouseClick(button, Qt::LeftButton);
QTest::qWait(1000);
}
}
// On MainWindow close we should get a message box telling the user to disconnect first. Cancel should do nothing.
setExpectedMessageBox(QGCMessageBox::Cancel);
_mainWindow->close();
......
......@@ -43,7 +43,6 @@ private slots:
void init(void);
void cleanup(void);
void _clickThrough_test(void);
void _connectWindowClosePX4_test(void);
void _connectWindowCloseGeneric_test(void);
......
This diff is collapsed.
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef MOCKLINK_H
......@@ -28,7 +28,7 @@
#include <QLoggingCategory>
#include "MockLinkMissionItemHandler.h"
#include "LinkInterface.h"
#include "LinkManager.h"
#include "QGCMAVLink.h"
Q_DECLARE_LOGGING_CATEGORY(MockLinkLog)
......@@ -38,14 +38,28 @@ Q_DECLARE_LOGGING_CATEGORY(MockLinkLog)
///
/// @author Don Gagne <don@thegagnes.com>
class MockConfiguration : public LinkConfiguration
{
public:
MockConfiguration(const QString& name) : LinkConfiguration(name) {}
MockConfiguration(MockConfiguration* source) : LinkConfiguration(source) {}
int type() { return LinkConfiguration::TypeMock; }
void copyFrom(LinkConfiguration* source) { LinkConfiguration::copyFrom(source); }
void loadSettings(QSettings& settings, const QString& root) { Q_UNUSED(settings); Q_UNUSED(root); }
void saveSettings(QSettings& settings, const QString& root) { Q_UNUSED(settings); Q_UNUSED(root); }
void updateSettings() {}
};
class MockLink : public LinkInterface
{
Q_OBJECT
public:
MockLink(void);
// LinkConfiguration is optional for MockLink
MockLink(MockConfiguration* config = NULL);
~MockLink(void);
// Virtuals from LinkInterface
virtual int getId(void) const { return _linkId; }
virtual QString getName(void) const { return _name; }
......@@ -53,40 +67,42 @@ public:
virtual bool isConnected(void) const { return _connected; }
virtual qint64 getConnectionSpeed(void) const { return 100000000; }
virtual qint64 bytesAvailable(void) { return 0; }
// MockLink methods
MAV_AUTOPILOT getAutopilotType(void) { return _autopilotType; }
void setAutopilotType(MAV_AUTOPILOT autopilot) { _autopilotType = autopilot; }
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
bool disconnect(void);
LinkConfiguration* getLinkConfiguration() { return _config; }
signals:
/// @brief Used internally to move data to the thread.
void _incomingBytes(const QByteArray bytes);
public slots:
virtual void writeBytes(const char *bytes, qint64 cBytes);
protected slots:
// FIXME: This should not be part of LinkInterface. It is an internal link implementation detail.
virtual void readBytes(void);
private slots:
void _run1HzTasks(void);
void _run10HzTasks(void);
void _run50HzTasks(void);
private:
// From LinkInterface
virtual bool _connect(void);
virtual bool _disconnect(void);
// QThread override
virtual void run(void);
// MockLink methods
void _sendHeartBeat(void);
void _handleIncomingBytes(const QByteArray bytes);
......@@ -106,27 +122,28 @@ private:
void _setParamFloatUnionIntoMap(const QString& paramName, float paramFloat);
MockLinkMissionItemHandler* _missionItemHandler;
int _linkId;
QString _name;
bool _connected;
uint8_t _vehicleSystemId;
uint8_t _vehicleComponentId;
bool _inNSH;
bool _mavlinkStarted;
QMap<QString, QVariant> _mapParamName2Value;
QMap<QString, MAV_PARAM_TYPE> _mapParamName2MavParamType;
typedef QMap<uint16_t, mavlink_mission_item_t> MissionList_t;
MissionList_t _missionItems;
uint8_t _mavBaseMode;
uint8_t _mavCustomMode;
uint8_t _mavState;
MockConfiguration* _config;
MAV_AUTOPILOT _autopilotType;
};
......
......@@ -381,7 +381,7 @@
1 50 RTL_RETURN_ALT 100 9
1 50 SDLOG_EXT -1 6
1 50 SDLOG_RATE -1 6
1 50 SENS_ACC_XOFF 0 9
1 50 SENS_ACC_XOFF 1 9
1 50 SENS_ACC_XSCALE 1 9
1 50 SENS_ACC_YOFF 0 9
1 50 SENS_ACC_YSCALE 1 9
......@@ -396,13 +396,13 @@
1 50 SENS_DPRES_OFF 0 9
1 50 SENS_EXT_MAG 0 6
1 50 SENS_EXT_MAG_ROT 0 6
1 50 SENS_GYRO_XOFF 0 9
1 50 SENS_GYRO_XOFF 1 9
1 50 SENS_GYRO_XSCALE 1 9
1 50 SENS_GYRO_YOFF 0 9
1 50 SENS_GYRO_YSCALE 1 9
1 50 SENS_GYRO_ZOFF 0 9
1 50 SENS_GYRO_ZSCALE 1 9
1 50 SENS_MAG_XOFF 0 9
1 50 SENS_MAG_XOFF 1 9
1 50 SENS_MAG_XSCALE 1 9
1 50 SENS_MAG_YOFF 0 9
1 50 SENS_MAG_YSCALE 1 9
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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