Commit e863bdae authored by Don Gagne's avatar Don Gagne

Use FactBinder to access facts from Qml

Passing parameters QVariantMap across C++ boundary was causing crashes
in Qt due to Qml array bugs. Referencing same Fact* across Qml boundary
in multiple QQuickWidgets caused jScript GC to crash.
parent 0eb51f49
......@@ -774,6 +774,7 @@ INCLUDEPATH += \
HEADERS += \
src/FactSystem/FactSystem.h \
src/FactSystem/Fact.h \
src/FactSystem/FactBinder.h \
src/FactSystem/FactMetaData.h \
src/FactSystem/FactValidator.h \
src/FactSystem/FactLoader.h \
......@@ -781,6 +782,7 @@ HEADERS += \
SOURCES += \
src/FactSystem/FactSystem.cc \
src/FactSystem/Fact.cc \
src/FactSystem/FactBinder.cc \
src/FactSystem/FactMetaData.cc \
src/FactSystem/FactValidator.cc \
src/FactSystem/FactLoader.cc \
......@@ -62,3 +62,13 @@ void AutoPilotPlugin::refreshParametersPrefix(const QString& paramPrefix)
}
}
}
bool AutoPilotPlugin::factExists(const QString& param)
{
return parameters().contains(param);
}
Fact* AutoPilotPlugin::getFact(const QString& name)
{
return parameters()[name].value<Fact*>();
}
......@@ -50,7 +50,6 @@ class AutoPilotPlugin : public QObject
public:
AutoPilotPlugin(UASInterface* uas, QObject* parent);
Q_PROPERTY(QVariantMap parameters READ parameters CONSTANT)
Q_PROPERTY(QVariantList components READ components CONSTANT)
Q_PROPERTY(QUrl setupBackgroundImage READ setupBackgroundImage CONSTANT)
......@@ -62,6 +61,10 @@ public:
// Request a refresh on all parameters that begin with the specified prefix
Q_INVOKABLE void refreshParametersPrefix(const QString& paramPrefix);
Q_INVOKABLE bool factExists(const QString& param);
Fact* getFact(const QString& name);
// Property accessors
virtual const QVariantList& components(void) = 0;
......
......@@ -3,6 +3,7 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
......@@ -13,10 +14,10 @@ Column {
width: parent.width
QGCLabel { id: systemId; text: "System ID:" }
QGCLabel {
FactLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - systemId.contentWidth
text: autopilot.parameters["MAV_SYS_ID"].value
fact: Fact { name: "MAV_SYS_ID" }
}
}
......@@ -25,9 +26,10 @@ Column {
QGCLabel { id: airframe; text: "Airframe:" }
QGCLabel {
property Fact fact: Fact { name: "SYS_AUTOSTART" }
horizontalAlignment: Text.AlignRight
width: parent.width - airframe.contentWidth
text: autopilot.parameters["SYS_AUTOSTART"].value == 0 ? "Setup required" : autopilot.parameters["SYS_AUTOSTART"].value
text: fact.value == 0 ? "Setup required" : fact.value
}
}
}
......@@ -9,47 +9,51 @@ Column {
anchors.fill: parent
anchors.margins: 8
Row {
width: parent.width
QGCLabel { id: mode; text: "Mode switch:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - mode.contentWidth
text: autopilot.parameters["RC_MAP_MODE_SW"].value == 0 ? "Setup required" : autopilot.parameters["RC_MAP_MODE_SW"].value
Component {
id: component
Row {
width: parent.width
QGCLabel { id: label; text: labelText }
QGCLabel {
property Fact fact: Fact { name: factName }
horizontalAlignment: Text.AlignRight
width: parent.width - label.contentWidth
text: fact.value == 0 ? zeroText : fact.value
}
}
}
Row {
Loader {
property string labelText: "Mode switch:"
property string zeroText: "Setup required"
property string factName: "RC_MAP_MODE_SW"
width: parent.width
QGCLabel { id: posctl; text: "Position Ctl switch:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - posctl.contentWidth
text: autopilot.parameters["RC_MAP_POSCTL_SW"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_POSCTL_SW"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Position Ctl switch:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_POSCTL_SW"
width: parent.width
QGCLabel { id: loiter; text: "Loiter switch:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - loiter.contentWidth
text: autopilot.parameters["RC_MAP_LOITER_SW"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_LOITER_SW"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Position Ctl switch:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_LOITER_SW"
width: parent.width
sourceComponent: component
}
QGCLabel { id: rtl; text: "Return switch:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - rtl.contentWidth
text: autopilot.parameters["RC_MAP_RETURN_SW"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_RETURN_SW"].value
}
Loader {
property string labelText: "Return switch:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_RETURN_SW"
width: parent.width
sourceComponent: component
}
}
......@@ -9,80 +9,75 @@ Column {
anchors.fill: parent
anchors.margins: 8
Row {
width: parent.width
QGCLabel { id: roll; text: "Roll:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - roll.contentWidth
text: autopilot.parameters["RC_MAP_ROLL"].value == 0 ? "Setup required" : autopilot.parameters["RC_MAP_ROLL"].value
Component {
id: component
Row {
width: parent.width
QGCLabel { id: label; text: labelText }
QGCLabel {
Fact { id: fact; name: factName }
horizontalAlignment: Text.AlignRight
width: parent.width - label.contentWidth
text: fact.value == 0 ? zeroText : fact.value
}
}
}
Row {
Loader {
property string labelText: "Roll:"
property string zeroText: "Setup required"
property string factName: "RC_MAP_ROLL"
width: parent.width
QGCLabel { id: pitch; text: "Pitch:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - pitch.contentWidth
text: autopilot.parameters["RC_MAP_PITCH"].value == 0 ? "Setup required" : autopilot.parameters["RC_MAP_PITCH"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Pitch:"
property string zeroText: "Setup required"
property string factName: "RC_MAP_PITCH"
width: parent.width
QGCLabel { id: yaw; text: "Yaw:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - yaw.contentWidth
text: autopilot.parameters["RC_MAP_YAW"].value == 0 ? "Setup required" : autopilot.parameters["RC_MAP_YAW"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Yaw:"
property string zeroText: "Setup required"
property string factName: "RC_MAP_YAW"
width: parent.width
QGCLabel { id: throttle; text: "Throttle:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - throttle.contentWidth
text: autopilot.parameters["RC_MAP_THROTTLE"].value == 0 ? "Setup required" : autopilot.parameters["RC_MAP_THROTTLE"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Throttle:"
property string zeroText: "Setup required"
property string factName: "RC_MAP_THROTTLE"
width: parent.width
QGCLabel { id: flaps; text: "Flaps:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - flaps.contentWidth
text: autopilot.parameters["RC_MAP_FLAPS"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_FLAPS"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Flaps:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_FLAPS"
width: parent.width
QGCLabel { id: aux1; text: "Aux1:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - aux1.contentWidth
text: autopilot.parameters["RC_MAP_AUX1"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_AUX1"].value
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Aux1:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_AUX1"
width: parent.width
sourceComponent: component
}
QGCLabel { id: aux2; text: "Aux2:" }
QGCLabel {
horizontalAlignment: Text.AlignRight
width: parent.width - aux2.contentWidth
text: autopilot.parameters["RC_MAP_AUX2"].value == 0 ? "Disabled" : autopilot.parameters["RC_MAP_AUX2"].value
}
Loader {
property string labelText: "Aux2:"
property string zeroText: "Disabled"
property string factName: "RC_MAP_AUX2"
width: parent.width
sourceComponent: component
}
}
......@@ -61,7 +61,7 @@ Rectangle {
QGCLabel { text: "Return Home after"; anchors.baseline: rcLossField.baseline }
FactTextField {
id: rcLossField
fact: autopilot.parameters["COM_RC_LOSS_T"]
fact: Fact { name: "COM_RC_LOSS_T" }
showUnits: true
}
}
......@@ -70,7 +70,7 @@ Rectangle {
spacing: 10
FactCheckBox {
id: telemetryTimeoutCheckbox
fact: autopilot.parameters["COM_DL_LOSS_EN"]
fact: Fact { name: "COM_DL_LOSS_EN" }
checkedValue: 1
uncheckedValue: 0
text: "Telemetry Signal Timeout"
......@@ -80,7 +80,7 @@ Rectangle {
QGCLabel { text: "Return Home after"; anchors.baseline: telemetryLossField.baseline }
FactTextField {
id: telemetryLossField
fact: autopilot.parameters["COM_DL_LOSS_T"];
fact: Fact { name: "COM_DL_LOSS_T" }
showUnits: true
enabled: telemetryTimeoutCheckbox.checked
}
......@@ -125,7 +125,7 @@ Rectangle {
QGCLabel { text: "Climb to altitude of" }
FactTextField {
id: climbField
fact: autopilot.parameters["RTL_RETURN_ALT"]
fact: Fact { name: "RTL_RETURN_ALT" }
showUnits: true
}
}
......@@ -137,7 +137,8 @@ Rectangle {
QGCCheckBox {
id: homeLoiterCheckbox
property Fact fact: autopilot.parameters["RTL_LAND_DELAY"]
property Fact fact: Fact { name: "RTL_LAND_DELAY" }
checked: fact.value > 0
text: "Loiter at Home altitude for"
onClicked: {
......@@ -145,7 +146,7 @@ Rectangle {
}
}
FactTextField {
fact: autopilot.parameters["RTL_LAND_DELAY"];
fact: Fact { name: "RTL_LAND_DELAY" }
showUnits: true
enabled: homeLoiterCheckbox.checked == true
}
......@@ -251,7 +252,7 @@ Rectangle {
}
FactTextField {
id: descendField;
fact: autopilot.parameters["RTL_DESCEND_ALT"];
fact: Fact { name: "RTL_DESCEND_ALT" }
enabled: homeLoiterCheckbox.checked == true
showUnits: true
}
......@@ -263,17 +264,19 @@ Rectangle {
}
QGCLabel {
property Fact fact: Fact { name: "NAV_RCL_OBC" }
width: parent.width
font.pointSize: 14
text: "Warning: You have an advanced safety configuration set using the NAV_RCL_OBC parameter. The above settings may not apply.";
visible: autopilot.parameters["NAV_RCL_OBC"].value != 0
visible: fact.value != 0
wrapMode: Text.Wrap
}
QGCLabel {
property Fact fact: Fact { name: "NAV_DLL_OBC" }
width: parent.width
font.pointSize: 14
text: "Warning: You have an advanced safety configuration set using the NAV_DLL_OBC parameter. The above settings may not apply.";
visible: autopilot.parameters["NAV_DLL_OBC"].value != 0
visible: fact.value != 0
wrapMode: Text.Wrap
}
}
......
......@@ -3,6 +3,7 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
......@@ -13,10 +14,10 @@ Column {
width: parent.width
QGCLabel { id: rtlMinAlt; text: "RTL min alt:" }
QGCLabel {
FactLabel {
fact: Fact { name: "RTL_RETURN_ALT" }
horizontalAlignment: Text.AlignRight;
width: parent.width - rtlMinAlt.contentWidth;
text: autopilot.parameters["RTL_RETURN_ALT"].valueString
}
}
......@@ -24,10 +25,10 @@ Column {
width: parent.width
QGCLabel { id: rtlHomeAlt; text: "RTL home alt:" }
QGCLabel {
FactLabel {
fact: Fact { name: "RTL_DESCEND_ALT" }
horizontalAlignment: Text.AlignRight;
width: parent.width - rtlHomeAlt.contentWidth;
text: autopilot.parameters["RTL_DESCEND_ALT"].valueString
}
}
......@@ -36,9 +37,10 @@ Column {
QGCLabel { id: rtlLoiter; text: "RTL loiter delay:" }
QGCLabel {
property Fact fact: Fact { name: "RTL_LAND_DELAY" }
horizontalAlignment: Text.AlignRight;
width: parent.width - rtlLoiter.contentWidth;
text: autopilot.parameters["RTL_LAND_DELAY"].value < 0 ? "Disabled" : autopilot.parameters["RTL_LAND_DELAY"].valueString
text: fact.value < 0 ? "Disabled" : fact.valueString
}
}
......@@ -47,9 +49,10 @@ Column {
QGCLabel { id: commLoss; text: "Telemetry loss RTL:" }
QGCLabel {
property Fact fact: Fact { name: "COM_DL_LOSS_EN" }
horizontalAlignment: Text.AlignRight;
width: parent.width - commLoss.contentWidth;
text: autopilot.parameters["COM_DL_LOSS_EN"].value != 1 ? "Disabled" : autopilot.parameters["COM_DL_LOSS_T"].valueString
text: fact.value != 1 ? "Disabled" : fact.valueString
}
}
......@@ -57,10 +60,10 @@ Column {
width: parent.width
QGCLabel { id: rcLoss; text: "RC loss RTL (seconds):" }
QGCLabel {
FactLabel {
fact: Fact { name: "COM_RC_LOSS_T" }
horizontalAlignment: Text.AlignRight;
width: parent.width - rcLoss.contentWidth;
text: autopilot.parameters["COM_RC_LOSS_T"].valueString
}
}
}
......@@ -75,33 +75,41 @@ Rectangle {
QGCLabel { text: "Calibrate:"; anchors.baseline: firstButton.baseline }
IndicatorButton {
property Fact fact: Fact { name: "CAL_MAG0_ID" }
id: firstButton
width: parent.buttonWidth
text: "Compass"
indicatorGreen: autopilot.parameters["CAL_MAG0_ID"].value != 0
indicatorGreen: fact.value != 0
onClicked: controller.calibrateCompass()
}
IndicatorButton {
property Fact fact: Fact { name: "CAL_GYRO0_ID" }
width: parent.buttonWidth
text: "Gyroscope"
indicatorGreen: autopilot.parameters["CAL_GYRO0_ID"].value != 0
indicatorGreen: fact.value != 0
onClicked: controller.calibrateGyro()
}
IndicatorButton {
property Fact fact: Fact { name: "CAL_ACC0_ID" }
width: parent.buttonWidth
text: "Accelerometer"
indicatorGreen: autopilot.parameters["CAL_ACC0_ID"].value != 0
indicatorGreen: fact.value != 0
onClicked: controller.calibrateAccel()
}
IndicatorButton {
property Fact fact: Fact { name: "SENS_DPRES_OFF" }
width: parent.buttonWidth
text: "Airspeed"
visible: controller.fixedWing
indicatorGreen: autopilot.parameters["SENS_DPRES_OFF"].value != 0
onClicked: controller.calibrateAirspeed()
indicatorGreen: fact.value != 0
onClicked: controller.calibrateAirspeed()
}
}
......@@ -232,11 +240,15 @@ Rectangle {
}
Column {
property Fact cal_mag0_rot: Fact { name: "CAL_MAG0_ROT" }
property Fact cal_mag1_rot: Fact { name: "CAL_MAG1_ROT" }
property Fact cal_mag2_rot: Fact { name: "CAL_MAG2_ROT" }
// Compass rotation parameter < 0 indicates either internal compass, or no compass. So in
// both those cases we do not show a rotation combo.
property bool showCompass0: autopilot.parameters["CAL_MAG0_ROT"].value >= 0
property bool showCompass1: autopilot.parameters["CAL_MAG1_ROT"].value >= 0
property bool showCompass2: autopilot.parameters["CAL_MAG2_ROT"].value >= 0
property bool showCompass0: cal_mag0_rot.value >= 0
property bool showCompass1: cal_mag1_rot.value >= 0
property bool showCompass2: cal_mag2_rot.value >= 0
x: parent.width - rotationColumnWidth
......@@ -245,7 +257,7 @@ Rectangle {
FactComboBox {
width: rotationColumnWidth;
model: rotations
fact: autopilot.parameters["SENS_BOARD_ROT"]
fact: Fact { name: "SENS_BOARD_ROT" }
}
// Compass 0 rotation
......@@ -260,7 +272,7 @@ Rectangle {
FactComboBox {
width: rotationColumnWidth
model: rotations
fact: autopilot.parameters["CAL_MAG0_ROT"]
fact: Fact { name: "CAL_MAG0_ROT" }
}
}
Loader { sourceComponent: parent.showCompass0 ? compass0ComponentLabel : null }
......@@ -278,7 +290,7 @@ Rectangle {
FactComboBox {
width: rotationColumnWidth
model: rotations
fact: autopilot.parameters["CAL_MAG1_ROT"]
fact: Fact { name: "CAL_MAG1_ROT" }
}
}
Loader { sourceComponent: parent.showCompass1 ? compass1ComponentLabel : null }
......@@ -296,7 +308,7 @@ Rectangle {
FactComboBox {
width: rotationColumnWidth
model: rotations
fact: autopilot.parameters["CAL_MAG2_ROT"]
fact: Fact { name: "CAL_MAG2_ROT" }
}
}
Loader { sourceComponent: parent.showCompass2 ? compass2ComponentLabel : null }
......
......@@ -13,36 +13,40 @@ Column {
anchors.fill: parent
anchors.margins: 8
Row {
width: parent.width
QGCLabel { id: compass; text: "Compass:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: autopilot.parameters["CAL_MAG0_ID"].value == 0 ? "Setup required" : "Ready"
Component {
id: component
Row {
width: parent.width
QGCLabel { id: label; text: labelText }
QGCLabel {
property Fact fact: Fact { name: factName }
horizontalAlignment: Text.AlignRight;
width: parent.width - label.contentWidth;
text: fact.value == 0 ? "Setup required" : "Ready"
}
}
}
Row {
Loader {
property string labelText: "Compass:"
property string factName: "CAL_MAG0_ID"
width: parent.width
QGCLabel { id: gyro; text: "Gyro:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - gyro.contentWidth;
text: autopilot.parameters["CAL_GYRO0_ID"].value == 0 ? "Setup required" : "Ready"
}
sourceComponent: component
}
Row {
Loader {
property string labelText: "Gyro:"
property string factName: "CAL_GYRO0_ID"
width: parent.width
sourceComponent: component
}
QGCLabel { id: accel; text: "Accelerometer:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - accel.contentWidth;
text: autopilot.parameters["CAL_ACC0_ID"].value == 0 ? "Setup required" : "Ready"
}
Loader {
property string labelText: "Accelerometer:"
property string factName: "CAL_ACC0_ID"
width: parent.width
sourceComponent: component
}
}
......@@ -18,9 +18,10 @@ Column {
QGCLabel { id: compass; text: "Compass:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: autopilot.parameters["CAL_MAG0_ID"].value == 0 ? "Setup required" : "Ready"
property Fact fact: Fact { name: "CAL_MAG0_ID" }
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: fact.value == 0 ? "Setup required" : "Ready"
}
}
......@@ -29,9 +30,10 @@ Column {
QGCLabel { id: gyro; text: "Gyro:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - gyro.contentWidth;
text: autopilot.parameters["CAL_GYRO0_ID"].value == 0 ? "Setup required" : "Ready"
property Fact fact: Fact { name: "CAL_GYRO0_ID" }
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: fact.value == 0 ? "Setup required" : "Ready"
}
}
......@@ -40,9 +42,10 @@ Column {
QGCLabel { id: accel; text: "Accelerometer:" }
QGCLabel {
horizontalAlignment: Text.AlignRight;
width: parent.width - accel.contentWidth;
text: autopilot.parameters["CAL_ACC0_ID"].value == 0 ? "Setup required" : "Ready"
property Fact fact: Fact { name: "CAL_ACC0_ID" }
horizontalAlignment: Text.AlignRight;
width: parent.width - compass.contentWidth;
text: fact.value == 0 ? "Setup required" : "Ready"
}
}
......@@ -51,9 +54,10 @@ Column {
QGCLabel { id: airspeed; text: "Airspeed:" }
QGCLabel {
property Fact fact: Fact { name: "SENS_DPRES_OFF" }
horizontalAlignment: Text.AlignRight;
width: parent.width - airspeed.contentWidth;
text: autopilot.parameters["SENS_DPRES_OFF"].value == 0.0 ? "Setup required" : "Ready"
text: fact.value == 0.0 ? "Setup required" : "Ready"
}
}
}
/*=====================================================================
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