Commit fb26f834 authored by Don Gagne's avatar Don Gagne

Parameter validation support

parent a9d84d8e
......@@ -106,6 +106,7 @@
<file alias="QGroundControl/Controls/QGCViewMessage.qml">src/QmlControls/QGCViewMessage.qml</file>
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="ParameterEditorWidget.qml">src/ViewWidgets/ParameterEditorWidget.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
......
......@@ -51,34 +51,19 @@ Fact::Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObjec
void Fact::setValue(const QVariant& value)
{
QVariant newValue;
switch (type()) {
case FactMetaData::valueTypeInt8:
case FactMetaData::valueTypeInt16:
case FactMetaData::valueTypeInt32:
newValue = QVariant(value.toInt());
break;
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeUint16:
case FactMetaData::valueTypeUint32:
newValue = QVariant(value.toUInt());
break;
case FactMetaData::valueTypeFloat:
newValue = QVariant(value.toFloat());
break;
case FactMetaData::valueTypeDouble:
newValue = QVariant(value.toDouble());
break;
}
if (newValue != _value) {
_value.setValue(newValue);
emit valueChanged(_value);
emit _containerValueChanged(_value);
if (_metaData) {
QVariant typedValue;
QString errorString;
if (_metaData->convertAndValidate(value, true /* convertOnly */, typedValue, errorString)) {
if (typedValue != _value) {
_value.setValue(typedValue);
emit valueChanged(_value);
emit _containerValueChanged(_value);
}
}
} else {
qWarning() << "Meta data pointer missing";
}
}
......@@ -110,11 +95,15 @@ QString Fact::valueString(void) const
QVariant Fact::defaultValue(void)
{
Q_ASSERT(_metaData);
if (!_metaData->defaultValueAvailable()) {
qDebug() << "Access to unavailable default value";
if (_metaData) {
if (!_metaData->defaultValueAvailable()) {
qDebug() << "Access to unavailable default value";
}
return _metaData->defaultValue();
} else {
qWarning() << "Meta data pointer missing";
return QVariant(0);
}
return _metaData->defaultValue();
}
FactMetaData::ValueType_t Fact::type(void)
......@@ -124,38 +113,82 @@ FactMetaData::ValueType_t Fact::type(void)
QString Fact::shortDescription(void)
{
Q_ASSERT(_metaData);
return _metaData->shortDescription();
if (_metaData) {
return _metaData->shortDescription();
} else {
qWarning() << "Meta data pointer missing";
return QString();
}
}
QString Fact::longDescription(void)
{
Q_ASSERT(_metaData);
return _metaData->longDescription();
if (_metaData) {
return _metaData->longDescription();
} else {
qWarning() << "Meta data pointer missing";
return QString();
}
}
QString Fact::units(void)
{
Q_ASSERT(_metaData);
return _metaData->units();
if (_metaData) {
return _metaData->units();
} else {
qWarning() << "Meta data pointer missing";
return QString();
}
}
QVariant Fact::min(void)
{
Q_ASSERT(_metaData);
return _metaData->min();
if (_metaData) {
return _metaData->min();
} else {
qWarning() << "Meta data pointer missing";
return QVariant(0);
}
}
QVariant Fact::max(void)
{
Q_ASSERT(_metaData);
return _metaData->max();
if (_metaData) {
return _metaData->max();
} else {
qWarning() << "Meta data pointer missing";
return QVariant(0);
}
}
bool Fact::minIsDefaultForType(void)
{
if (_metaData) {
return _metaData->minIsDefaultForType();
} else {
qWarning() << "Meta data pointer missing";
return false;
}
}
bool Fact::maxIsDefaultForType(void)
{
if (_metaData) {
return _metaData->maxIsDefaultForType();
} else {
qWarning() << "Meta data pointer missing";
return false;
}
}
QString Fact::group(void)
{
Q_ASSERT(_metaData);
return _metaData->group();
if (_metaData) {
return _metaData->group();
} else {
qWarning() << "Meta data pointer missing";
return QString();
}
}
void Fact::setMetaData(FactMetaData* metaData)
......@@ -165,16 +198,40 @@ void Fact::setMetaData(FactMetaData* metaData)
bool Fact::valueEqualsDefault(void)
{
Q_ASSERT(_metaData);
if (_metaData->defaultValueAvailable()) {
return _metaData->defaultValue() == value();
if (_metaData) {
if (_metaData->defaultValueAvailable()) {
return _metaData->defaultValue() == value();
} else {
return false;
}
} else {
qWarning() << "Meta data pointer missing";
return false;
}
}
bool Fact::defaultValueAvailable(void)
{
Q_ASSERT(_metaData);
return _metaData->defaultValueAvailable();
}
\ No newline at end of file
if (_metaData) {
return _metaData->defaultValueAvailable();
} else {
qWarning() << "Meta data pointer missing";
return false;
}
}
QString Fact::validate(const QString& value, bool convertOnly)
{
if (_metaData) {
QVariant typedValue;
QString errorString;
_metaData->convertAndValidate(value, convertOnly, typedValue, errorString);
return errorString;
} else {
qWarning() << "Meta data pointer missing";
return QString("Internal error: Meta data pointer missing");
}
}
......@@ -55,9 +55,15 @@ public:
Q_PROPERTY(QString shortDescription READ shortDescription CONSTANT)
Q_PROPERTY(QString longDescription READ longDescription CONSTANT)
Q_PROPERTY(QVariant min READ min CONSTANT)
Q_PROPERTY(bool minIsDefaultForType READ minIsDefaultForType CONSTANT)
Q_PROPERTY(QVariant max READ max CONSTANT)
Q_PROPERTY(bool maxIsDefaultForType READ maxIsDefaultForType CONSTANT)
Q_PROPERTY(QString group READ group CONSTANT)
/// Convert and validate value
/// @param convertOnly true: validate type conversion only, false: validate against meta data as well
Q_INVOKABLE QString validate(const QString& value, bool convertOnly);
// Property system methods
QString name(void) const;
......@@ -73,7 +79,9 @@ public:
QString longDescription(void);
QString units(void);
QVariant min(void);
bool minIsDefaultForType(void);
QVariant max(void);
bool maxIsDefaultForType(void);
QString group(void);
/// Sets the meta data associated with the Fact.
......
......@@ -39,7 +39,9 @@ FactMetaData::FactMetaData(ValueType_t type, QObject* parent) :
_defaultValue(0),
_defaultValueAvailable(false),
_min(_minForType()),
_max(_maxForType())
_max(_maxForType()),
_minIsDefaultForType(true),
_maxIsDefaultForType(true)
{
}
......@@ -68,6 +70,7 @@ void FactMetaData::setMin(const QVariant& min)
{
if (min > _minForType()) {
_min = min;
_minIsDefaultForType = false;
} else {
qWarning() << "Attempt to set min below allowable value";
_min = _minForType();
......@@ -81,6 +84,7 @@ void FactMetaData::setMax(const QVariant& max)
_max = _maxForType();
} else {
_max = max;
_maxIsDefaultForType = false;
}
}
......@@ -133,3 +137,58 @@ QVariant FactMetaData::_maxForType(void)
// Make windows compiler happy, even switch is full cased
return QVariant();
}
bool FactMetaData::convertAndValidate(const QVariant& value, bool convertOnly, QVariant& typedValue, QString& errorString)
{
bool convertOk;
errorString.clear();
switch (type()) {
case FactMetaData::valueTypeInt8:
case FactMetaData::valueTypeInt16:
case FactMetaData::valueTypeInt32:
typedValue = QVariant(value.toInt(&convertOk));
if (!convertOnly && convertOk) {
if (min() > typedValue || typedValue > max()) {
errorString = QString("Value must be within %1 and %2").arg(min().toInt()).arg(max().toInt());
}
}
break;
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeUint16:
case FactMetaData::valueTypeUint32:
typedValue = QVariant(value.toUInt(&convertOk));
if (!convertOnly && convertOk) {
if (min() > typedValue || typedValue > max()) {
errorString = QString("Value must be within %1 and %2").arg(min().toUInt()).arg(max().toUInt());
}
}
break;
case FactMetaData::valueTypeFloat:
typedValue = QVariant(value.toFloat(&convertOk));
if (!convertOnly && convertOk) {
if (min() > typedValue || typedValue > max()) {
errorString = QString("Value must be within %1 and %2").arg(min().toFloat()).arg(max().toFloat());
}
}
break;
case FactMetaData::valueTypeDouble:
typedValue = QVariant(value.toDouble(&convertOk));
if (!convertOnly && convertOk) {
if (min() > typedValue || typedValue > max()) {
errorString = QString("Value must be within %1 and %2").arg(min().toDouble()).arg(max().toDouble());
}
}
break;
}
if (!convertOk) {
errorString = "Invalid number";
}
return convertOk && errorString.isEmpty();
}
......@@ -55,6 +55,7 @@ public:
FactMetaData(ValueType_t type, QObject* parent = NULL);
// Property accessors
QString name(void) { return _name; }
QString group(void) { return _group; }
ValueType_t type(void) { return _type; }
QVariant defaultValue(void);
......@@ -64,8 +65,11 @@ public:
QString units(void) { return _units; }
QVariant min(void) { return _min; }
QVariant max(void) { return _max; }
bool minIsDefaultForType(void) { return _minIsDefaultForType; }
bool maxIsDefaultForType(void) { return _maxIsDefaultForType; }
// Property setters
void setName(const QString& name) { _name = name; }
void setGroup(const QString& group) { _group = group; }
void setDefaultValue(const QVariant& defaultValue);
void setShortDescription(const QString& shortDescription) { _shortDescription = shortDescription; }
......@@ -73,11 +77,20 @@ public:
void setUnits(const QString& units) { _units = units; }
void setMin(const QVariant& max);
void setMax(const QVariant& max);
/// Converts the specified value, validating against meta data
/// @param value Value to convert, can be string
/// @param convertOnly true: convert to correct type only, do not validate against meta data
/// @param typeValue Converted value, correctly typed
/// @param errorString Error string if convert fails
/// @returns false: Convert failed, errorString set
bool convertAndValidate(const QVariant& value, bool convertOnly, QVariant& typedValue, QString& errorString);
private:
QVariant _minForType(void);
QVariant _maxForType(void);
QString _name;
QString _group;
ValueType_t _type;
QVariant _defaultValue;
......@@ -87,6 +100,8 @@ private:
QString _units;
QVariant _min;
QVariant _max;
bool _minIsDefaultForType;
bool _maxIsDefaultForType;
};
#endif
\ No newline at end of file
......@@ -167,6 +167,11 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
if (fullLogging) {
QLoggingCategory::setFilterRules(QStringLiteral("*Log=true"));
} else {
if (_runningUnitTests) {
// We need to turn off these warnings until the firmware meta data is cleaned up
QLoggingCategory::setFilterRules(QStringLiteral("PX4ParameterLoaderLog.warning=false"));
}
// First thing we want to do is set up the qtlogging.ini file. If it doesn't already exist we copy
// it to the correct location. This way default debug builds will have logging turned off.
......
This diff is collapsed.
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2015 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>
import QtQuick 2.3
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controllers 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
QGCViewDialog {
property Fact fact
property bool validate: false
property string validateValue
ParameterEditorController { id: controller; factPanel: parent }
function accept() {
var errorString = fact.validate(valueField.text, forceSave.checked)
if (errorString == "") {
fact.value = valueField.text
fact.valueChanged(fact.value)
hideDialog()
} else {
validationError.text = errorString
forceSave.visible = true
}
}
Component.onCompleted: {
if (validate) {
validationError.text = fact.validate(validateValue, false /* convertOnly */)
forceSave.visible = true
}
}
Column {
spacing: defaultTextHeight
anchors.left: parent.left
anchors.right: parent.right
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: fact.shortDescription ? fact.shortDescription : "Description missing"
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
visible: fact.longDescription
text: fact.longDescription
}
QGCTextField {
id: valueField
text: validate ? validateValue : fact.valueString
}
QGCLabel { text: fact.name }
Row {
spacing: defaultTextWidth
QGCLabel { text: "Units:" }
QGCLabel { text: fact.units ? fact.units : "none" }
}
Row {
spacing: defaultTextWidth
visible: !fact.minIsDefaultForType
QGCLabel { text: "Minimum value:" }
QGCLabel { text: fact.min }
}
Row {
spacing: defaultTextWidth
visible: !fact.maxIsDefaultForType
QGCLabel { text: "Maximum value:" }
QGCLabel { text: fact.max }
}
Row {
spacing: defaultTextWidth
QGCLabel { text: "Default value:" }
QGCLabel { text: fact.defaultValueAvailable ? fact.defaultValue : "none" }
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: "Warning: Modifying parameters while vehicle is in flight can lead to vehicle instability and possible vehicle loss. " +
"Make sure you know what you are doing and double-check your values before Save!"
}
QGCLabel {
id: validationError
width: parent.width
wrapMode: Text.WordWrap
color: "yellow"
}
QGCCheckBox {
id: forceSave
visible: false
text: "Force save (dangerous!)"
}
} // Column - Fact information
QGCButton {
id: bottomButton
anchors.rightMargin: defaultTextWidth
anchors.right: rcButton.left
anchors.bottom: parent.bottom
visible: fact.defaultValueAvailable
text: "Reset to default"
onClicked: {
fact.value = fact.defaultValue
fact.valueChanged(fact.value)
hideDialog()
}
}
QGCButton {
id: rcButton
anchors.right: parent.right
anchors.bottom: parent.bottom
text: "Set RC to Param..."
visible: !validate
onClicked: controller.setRCToParam(fact.name)
}
} // QGCViewDialog
......@@ -14,9 +14,11 @@ SubMenuButton 1.0 SubMenuButton.qml
IndicatorButton 1.0 IndicatorButton.qml
VehicleRotationCal 1.0 VehicleRotationCal.qml
VehicleSummaryRow 1.0 VehicleSummaryRow.qml
ParameterEditor 1.0 ParameterEditor.qml
ViewWidget 1.0 ViewWidget.qml
ParameterEditor 1.0 ParameterEditor.qml
ParameterEditorDialog 1.0 ParameterEditorDialog.qml
QGCView 1.0 QGCView.qml
QGCViewPanel 1.0 QGCViewPanel.qml
QGCViewDialog 1.0 QGCViewDialog.qml
......
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