1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +01:00

Conflicts:

ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjectbrowserconfiguration.cpp
	ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp
	ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h
This commit is contained in:
m_thread 2014-10-16 00:11:19 +02:00
commit 77ebb4fe74
28 changed files with 1265 additions and 77 deletions

View File

@ -0,0 +1,559 @@
/*
Copyright 2012, Robert Knight
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*/
#include "mustache.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
using namespace Mustache;
QString Mustache::renderTemplate(const QString & templateString, const QVariantHash & args)
{
Mustache::QtVariantContext context(args);
Mustache::Renderer renderer;
return renderer.render(templateString, &context);
}
QString escapeHtml(const QString & input)
{
QString escaped(input);
for (int i = 0; i < escaped.count();) {
const char *replacement = 0;
ushort ch = escaped.at(i).unicode();
if (ch == '&') {
replacement = "&amp;";
} else if (ch == '<') {
replacement = "&lt;";
} else if (ch == '>') {
replacement = "&gt;";
} else if (ch == '"') {
replacement = "&quot;";
}
if (replacement) {
escaped.replace(i, 1, QLatin1String(replacement));
i += strlen(replacement);
} else {
++i;
}
}
return escaped;
}
QString unescapeHtml(const QString & escaped)
{
QString unescaped(escaped);
unescaped.replace(QLatin1String("&lt;"), QLatin1String("<"));
unescaped.replace(QLatin1String("&gt;"), QLatin1String(">"));
unescaped.replace(QLatin1String("&amp;"), QLatin1String("&"));
unescaped.replace(QLatin1String("&quot;"), QLatin1String("\""));
return unescaped;
}
Context::Context(PartialResolver *resolver)
: m_partialResolver(resolver)
{}
PartialResolver *Context::partialResolver() const
{
return m_partialResolver;
}
QString Context::partialValue(const QString & key) const
{
if (!m_partialResolver) {
return QString();
}
return m_partialResolver->getPartial(key);
}
bool Context::canEval(const QString &) const
{
return false;
}
QString Context::eval(const QString & key, const QString & _template, Renderer *renderer)
{
Q_UNUSED(key);
Q_UNUSED(_template);
Q_UNUSED(renderer);
return QString();
}
QtVariantContext::QtVariantContext(const QVariant & root, PartialResolver *resolver)
: Context(resolver)
{
m_contextStack << root;
}
QVariant variantMapValue(const QVariant & value, const QString & key)
{
if (value.userType() == QVariant::Map) {
return value.toMap().value(key);
} else {
return value.toHash().value(key);
}
}
QVariant variantMapValueForKeyPath(const QVariant & value, const QStringList keyPath)
{
if (keyPath.count() > 1) {
QVariant firstValue = variantMapValue(value, keyPath.first());
return firstValue.isNull() ? QVariant() : variantMapValueForKeyPath(firstValue, keyPath.mid(1));
} else if (!keyPath.isEmpty()) {
return variantMapValue(value, keyPath.first());
}
return QVariant();
}
QVariant QtVariantContext::value(const QString & key) const
{
if (key == "." && !m_contextStack.isEmpty()) {
return m_contextStack.last();
}
QStringList keyPath = key.split(".");
for (int i = m_contextStack.count() - 1; i >= 0; i--) {
QVariant value = variantMapValueForKeyPath(m_contextStack.at(i), keyPath);
if (!value.isNull()) {
return value;
}
}
return QVariant();
}
bool QtVariantContext::isFalse(const QString & key) const
{
QVariant value = this->value(key);
switch (value.userType()) {
case QVariant::Bool:
return !value.toBool();
case QVariant::List:
return value.toList().isEmpty();
case QVariant::Hash:
return value.toHash().isEmpty();
case QVariant::Map:
return value.toMap().isEmpty();
default:
return value.toString().isEmpty();
}
}
QString QtVariantContext::stringValue(const QString & key) const
{
if (isFalse(key)) {
return QString();
}
return value(key).toString();
}
void QtVariantContext::push(const QString & key, int index)
{
QVariant mapItem = value(key);
if (index == -1) {
m_contextStack << mapItem;
} else {
QVariantList list = mapItem.toList();
m_contextStack << list.value(index, QVariant());
}
}
void QtVariantContext::pop()
{
m_contextStack.pop();
}
int QtVariantContext::listCount(const QString & key) const
{
if (value(key).userType() == QVariant::List) {
return value(key).toList().count();
}
return 0;
}
bool QtVariantContext::canEval(const QString & key) const
{
return value(key).canConvert<fn_t>();
}
QString QtVariantContext::eval(const QString & key, const QString & _template, Renderer *renderer)
{
QVariant fn = value(key);
if (fn.isNull()) {
return QString();
}
return fn.value<fn_t>() (_template, renderer, this);
}
PartialMap::PartialMap(const QHash<QString, QString> & partials)
: m_partials(partials)
{}
QString PartialMap::getPartial(const QString & name)
{
return m_partials.value(name);
}
PartialFileLoader::PartialFileLoader(const QString & basePath)
: m_basePath(basePath)
{}
QString PartialFileLoader::getPartial(const QString & name)
{
if (!m_cache.contains(name)) {
QString path = m_basePath + '/' + name + ".mustache";
QFile file(path);
if (file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
m_cache.insert(name, stream.readAll());
}
}
return m_cache.value(name);
}
Renderer::Renderer()
: m_errorPos(-1)
, m_defaultTagStartMarker("{{")
, m_defaultTagEndMarker("}}")
{}
QString Renderer::error() const
{
return m_error;
}
int Renderer::errorPos() const
{
return m_errorPos;
}
QString Renderer::errorPartial() const
{
return m_errorPartial;
}
QString Renderer::render(const QString & _template, Context *context)
{
m_error.clear();
m_errorPos = -1;
m_errorPartial.clear();
m_tagStartMarker = m_defaultTagStartMarker;
m_tagEndMarker = m_defaultTagEndMarker;
return render(_template, 0, _template.length(), context);
}
QString Renderer::render(const QString & _template, int startPos, int endPos, Context *context)
{
QString output;
int lastTagEnd = startPos;
while (m_errorPos == -1) {
Tag tag = findTag(_template, lastTagEnd, endPos);
if (tag.type == Tag::Null) {
output += _template.midRef(lastTagEnd, endPos - lastTagEnd);
break;
}
output += _template.midRef(lastTagEnd, tag.start - lastTagEnd);
switch (tag.type) {
case Tag::Value:
{
QString value = context->stringValue(tag.key);
if (tag.escapeMode == Tag::Escape) {
value = escapeHtml(value);
} else if (tag.escapeMode == Tag::Unescape) {
value = unescapeHtml(value);
}
output += value;
lastTagEnd = tag.end;
}
break;
case Tag::SectionStart:
{
Tag endTag = findEndTag(_template, tag, endPos);
if (endTag.type == Tag::Null) {
if (m_errorPos == -1) {
setError("No matching end tag found for section", tag.start);
}
} else {
int listCount = context->listCount(tag.key);
if (listCount > 0) {
for (int i = 0; i < listCount; i++) {
context->push(tag.key, i);
output += render(_template, tag.end, endTag.start, context);
context->pop();
}
} else if (context->canEval(tag.key)) {
output += context->eval(tag.key, _template.mid(tag.end, endTag.start - tag.end), this);
} else if (!context->isFalse(tag.key)) {
context->push(tag.key);
output += render(_template, tag.end, endTag.start, context);
context->pop();
}
lastTagEnd = endTag.end;
}
}
break;
case Tag::InvertedSectionStart:
{
Tag endTag = findEndTag(_template, tag, endPos);
if (endTag.type == Tag::Null) {
if (m_errorPos == -1) {
setError("No matching end tag found for inverted section", tag.start);
}
} else {
if (context->isFalse(tag.key)) {
output += render(_template, tag.end, endTag.start, context);
}
lastTagEnd = endTag.end;
}
}
break;
case Tag::SectionEnd:
setError("Unexpected end tag", tag.start);
lastTagEnd = tag.end;
break;
case Tag::Partial:
{
QString tagStartMarker = m_tagStartMarker;
QString tagEndMarker = m_tagEndMarker;
m_tagStartMarker = m_defaultTagStartMarker;
m_tagEndMarker = m_defaultTagEndMarker;
m_partialStack.push(tag.key);
QString partial = context->partialValue(tag.key);
output += render(partial, 0, partial.length(), context);
lastTagEnd = tag.end;
m_partialStack.pop();
m_tagStartMarker = tagStartMarker;
m_tagEndMarker = tagEndMarker;
}
break;
case Tag::SetDelimiter:
lastTagEnd = tag.end;
break;
case Tag::Comment:
lastTagEnd = tag.end;
break;
case Tag::Null:
break;
}
}
return output;
}
void Renderer::setError(const QString & error, int pos)
{
Q_ASSERT(!error.isEmpty());
Q_ASSERT(pos >= 0);
m_error = error;
m_errorPos = pos;
if (!m_partialStack.isEmpty()) {
m_errorPartial = m_partialStack.top();
}
}
Tag Renderer::findTag(const QString & content, int pos, int endPos)
{
int tagStartPos = content.indexOf(m_tagStartMarker, pos);
if (tagStartPos == -1 || tagStartPos >= endPos) {
return Tag();
}
int tagEndPos = content.indexOf(m_tagEndMarker, tagStartPos + m_tagStartMarker.length());
if (tagEndPos == -1) {
return Tag();
}
tagEndPos += m_tagEndMarker.length();
Tag tag;
tag.type = Tag::Value;
tag.start = tagStartPos;
tag.end = tagEndPos;
pos = tagStartPos + m_tagStartMarker.length();
endPos = tagEndPos - m_tagEndMarker.length();
QChar typeChar = content.at(pos);
if (typeChar == '#') {
tag.type = Tag::SectionStart;
tag.key = readTagName(content, pos + 1, endPos);
} else if (typeChar == '^') {
tag.type = Tag::InvertedSectionStart;
tag.key = readTagName(content, pos + 1, endPos);
} else if (typeChar == '/') {
tag.type = Tag::SectionEnd;
tag.key = readTagName(content, pos + 1, endPos);
} else if (typeChar == '!') {
tag.type = Tag::Comment;
} else if (typeChar == '>') {
tag.type = Tag::Partial;
tag.key = readTagName(content, pos + 1, endPos);
} else if (typeChar == '=') {
tag.type = Tag::SetDelimiter;
readSetDelimiter(content, pos + 1, tagEndPos - m_tagEndMarker.length());
} else {
if (typeChar == '&') {
tag.escapeMode = Tag::Unescape;
++pos;
} else if (typeChar == '{') {
tag.escapeMode = Tag::Raw;
++pos;
int endTache = content.indexOf('}', pos);
if (endTache == tag.end - m_tagEndMarker.length()) {
++tag.end;
} else {
endPos = endTache;
}
}
tag.type = Tag::Value;
tag.key = readTagName(content, pos, endPos);
}
if (tag.type != Tag::Value) {
expandTag(tag, content);
}
return tag;
}
QString Renderer::readTagName(const QString & content, int pos, int endPos)
{
QString name;
name.reserve(endPos - pos);
while (content.at(pos).isSpace()) {
++pos;
}
while (!content.at(pos).isSpace() && pos < endPos) {
name += content.at(pos);
++pos;
}
return name;
}
void Renderer::readSetDelimiter(const QString & content, int pos, int endPos)
{
QString startMarker;
QString endMarker;
while (content.at(pos).isSpace() && pos < endPos) {
++pos;
}
while (!content.at(pos).isSpace() && pos < endPos) {
if (content.at(pos) == '=') {
setError("Custom delimiters may not contain '='.", pos);
return;
}
startMarker += content.at(pos);
++pos;
}
while (content.at(pos).isSpace() && pos < endPos) {
++pos;
}
while (!content.at(pos).isSpace() && pos < endPos - 1) {
if (content.at(pos) == '=') {
setError("Custom delimiters may not contain '='.", pos);
return;
}
endMarker += content.at(pos);
++pos;
}
m_tagStartMarker = startMarker;
m_tagEndMarker = endMarker;
}
Tag Renderer::findEndTag(const QString & content, const Tag & startTag, int endPos)
{
int tagDepth = 1;
int pos = startTag.end;
while (true) {
Tag nextTag = findTag(content, pos, endPos);
if (nextTag.type == Tag::Null) {
return nextTag;
} else if (nextTag.type == Tag::SectionStart || nextTag.type == Tag::InvertedSectionStart) {
++tagDepth;
} else if (nextTag.type == Tag::SectionEnd) {
--tagDepth;
if (tagDepth == 0) {
if (nextTag.key != startTag.key) {
setError("Tag start/end key mismatch", nextTag.start);
return Tag();
}
return nextTag;
}
}
pos = nextTag.end;
}
return Tag();
}
void Renderer::setTagMarkers(const QString & startMarker, const QString & endMarker)
{
m_defaultTagStartMarker = startMarker;
m_defaultTagEndMarker = endMarker;
}
void Renderer::expandTag(Tag & tag, const QString & content)
{
int start = tag.start;
int end = tag.end;
// Move start to beginning of line.
while (start > 0 && content.at(start - 1) != QLatin1Char('\n')) {
--start;
if (!content.at(start).isSpace()) {
return; // Not standalone.
}
}
// Move end to one past end of line.
while (end <= content.size() && content.at(end - 1) != QLatin1Char('\n')) {
if (end < content.size() && !content.at(end).isSpace()) {
return; // Not standalone.
}
++end;
}
tag.start = start;
tag.end = end;
}

View File

@ -0,0 +1,266 @@
/*
Copyright 2012, Robert Knight
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*/
#pragma once
#include <QtCore/QStack>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include "utils_global.h"
#if __cplusplus >= 201103L
#include <functional> /* for std::function */
#endif
namespace Mustache {
class PartialResolver;
class Renderer;
/** Context is an interface that Mustache::Renderer::render() uses to
* fetch substitutions for template tags.
*/
class QTCREATOR_UTILS_EXPORT Context {
public:
/** Create a context. @p resolver is used to fetch the expansions for any {{>partial}} tags
* which appear in a template.
*/
explicit Context(PartialResolver *resolver = 0);
virtual ~Context() {}
/** Returns a string representation of the value for @p key in the current context.
* This is used to replace a Mustache value tag.
*/
virtual QString stringValue(const QString & key) const = 0;
/** Returns true if the value for @p key is 'false' or an empty list.
* 'False' values typically include empty strings, the boolean value false etc.
*
* When processing a section Mustache tag, the section is not rendered if the key
* is false, or for an inverted section tag, the section is only rendered if the key
* is false.
*/
virtual bool isFalse(const QString & key) const = 0;
/** Returns the number of items in the list value for @p key or 0 if
* the value for @p key is not a list.
*/
virtual int listCount(const QString & key) const = 0;
/** Set the current context to the value for @p key.
* If index is >= 0, set the current context to the @p index'th value
* in the list value for @p key.
*/
virtual void push(const QString & key, int index = -1) = 0;
/** Exit the current context. */
virtual void pop() = 0;
/** Returns the partial template for a given @p key. */
QString partialValue(const QString & key) const;
/** Returns the partial resolver passed to the constructor. */
PartialResolver *partialResolver() const;
/** Returns true if eval() should be used to render section tags using @p key.
* If canEval() returns true for a key, the renderer will pass the literal, unrendered
* block of text for the section to eval() and replace the section with the result.
*
* canEval() and eval() are equivalents for callable objects (eg. lambdas) in other
* Mustache implementations.
*
* The default implementation always returns false.
*/
virtual bool canEval(const QString & key) const;
/** Callback used to render a template section with the given @p key.
* @p renderer will substitute the original section tag with the result of eval().
*
* The default implementation returns an empty string.
*/
virtual QString eval(const QString & key, const QString & _template, Renderer *renderer);
private:
PartialResolver *m_partialResolver;
};
/** A context implementation which wraps a QVariantHash or QVariantMap. */
class QTCREATOR_UTILS_EXPORT QtVariantContext : public Context {
public:
/** Construct a QtVariantContext which wraps a dictionary in a QVariantHash
* or a QVariantMap.
*/
#if __cplusplus >= 201103L
typedef std::function<QString(const QString &, Mustache::Renderer *, Mustache::Context *)> fn_t;
#else
typedef QString (*fn_t)(const QString &, Mustache::Renderer *, Mustache::Context *);
#endif
explicit QtVariantContext(const QVariant & root, PartialResolver *resolver = 0);
virtual QString stringValue(const QString & key) const;
virtual bool isFalse(const QString & key) const;
virtual int listCount(const QString & key) const;
virtual void push(const QString & key, int index = -1);
virtual void pop();
virtual bool canEval(const QString & key) const;
virtual QString eval(const QString & key, const QString & _template, Mustache::Renderer *renderer);
private:
QVariant value(const QString & key) const;
QStack<QVariant> m_contextStack;
};
/** Interface for fetching template partials. */
class QTCREATOR_UTILS_EXPORT PartialResolver {
public:
virtual ~PartialResolver() {}
/** Returns the partial template with a given @p name. */
virtual QString getPartial(const QString & name) = 0;
};
/** A simple partial fetcher which returns templates from a map of (partial name -> template)
*/
class QTCREATOR_UTILS_EXPORT PartialMap : public PartialResolver {
public:
explicit PartialMap(const QHash<QString, QString> & partials);
virtual QString getPartial(const QString & name);
private:
QHash<QString, QString> m_partials;
};
/** A partial fetcher when loads templates from '<name>.mustache' files
* in a given directory.
*
* Once a partial has been loaded, it is cached for future use.
*/
class QTCREATOR_UTILS_EXPORT PartialFileLoader : public PartialResolver {
public:
explicit PartialFileLoader(const QString & basePath);
virtual QString getPartial(const QString & name);
private:
QString m_basePath;
QHash<QString, QString> m_cache;
};
/** Holds properties of a tag in a mustache template. */
struct Tag {
enum Type {
Null,
Value, /// A {{key}} or {{{key}}} tag
SectionStart, /// A {{#section}} tag
InvertedSectionStart, /// An {{^inverted-section}} tag
SectionEnd, /// A {{/section}} tag
Partial, /// A {{^partial}} tag
Comment, /// A {{! comment }} tag
SetDelimiter /// A {{=<% %>=}} tag
};
enum EscapeMode {
Escape,
Unescape,
Raw
};
Tag()
: type(Null)
, start(0)
, end(0)
, escapeMode(Escape)
{}
Type type;
QString key;
int start;
int end;
EscapeMode escapeMode;
};
/** Renders Mustache templates, replacing mustache tags with
* values from a provided context.
*/
class QTCREATOR_UTILS_EXPORT Renderer {
public:
Renderer();
/** Render a Mustache template, using @p context to fetch
* the values used to replace Mustache tags.
*/
QString render(const QString & _template, Context *context);
/** Returns a message describing the last error encountered by the previous
* render() call.
*/
QString error() const;
/** Returns the position in the template where the last error occurred
* when rendering the template or -1 if no error occurred.
*
* If the error occurred in a partial template, the returned position is the offset
* in the partial template.
*/
int errorPos() const;
/** Returns the name of the partial where the error occurred, or an empty string
* if the error occurred in the main template.
*/
QString errorPartial() const;
/** Sets the default tag start and end markers.
* This can be overridden within a template.
*/
void setTagMarkers(const QString & startMarker, const QString & endMarker);
private:
QString render(const QString & _template, int startPos, int endPos, Context *context);
Tag findTag(const QString & content, int pos, int endPos);
Tag findEndTag(const QString & content, const Tag & startTag, int endPos);
void setError(const QString & error, int pos);
void readSetDelimiter(const QString & content, int pos, int endPos);
static QString readTagName(const QString & content, int pos, int endPos);
/** Expands @p tag to fill the line, but only if it is standalone.
*
* The start position is moved to the beginning of the line. The end position is
* moved to one past the end of the line. If @p tag is not standalone, it is
* left unmodified.
*
* A tag is standalone if it is the only non-whitespace token on the the line.
*/
static void expandTag(Tag & tag, const QString & content);
QStack<QString> m_partialStack;
QString m_error;
int m_errorPos;
QString m_errorPartial;
QString m_tagStartMarker;
QString m_tagEndMarker;
QString m_defaultTagStartMarker;
QString m_defaultTagEndMarker;
};
/** A convenience function which renders a template using the given data. */
QString renderTemplate(const QString & templateString, const QVariantHash & args);
};
Q_DECLARE_METATYPE(Mustache::QtVariantContext::fn_t)

View File

@ -56,7 +56,8 @@ SOURCES += reloadpromptutils.cpp \
svgimageprovider.cpp \
hostosinfo.cpp \
logfile.cpp \
crc.cpp
crc.cpp \
mustache.cpp
SOURCES += xmlconfig.cpp
@ -115,7 +116,8 @@ HEADERS += utils_global.h \
svgimageprovider.h \
hostosinfo.h \
logfile.h \
crc.h
crc.h \
mustache.h
HEADERS += xmlconfig.h

View File

@ -187,14 +187,12 @@ void ConfigStabilizationWidget::updateThrottleCurveFromObject()
UAVObject *stabBank = getObjectManager()->getObject(QString(m_pidTabBars.at(0)->tabData(m_currentPIDBank).toString()));
Q_ASSERT(stabBank);
qDebug() << "updatingCurveFromObject" << stabBank->getName();
UAVObjectField *field = stabBank->getField("ThrustPIDScaleCurve");
Q_ASSERT(field);
QList<double> curve;
for (quint32 i = 0; i < field->getNumElements(); i++) {
qDebug() << field->getName() << field->getElementNames().at(i) << "=>" << field->getValue(i);
curve.append(field->getValue(i).toDouble());
}
@ -214,7 +212,6 @@ void ConfigStabilizationWidget::updateObjectFromThrottleCurve()
UAVObject *stabBank = getObjectManager()->getObject(QString(m_pidTabBars.at(0)->tabData(m_currentPIDBank).toString()));
Q_ASSERT(stabBank);
qDebug() << "updatingObjectFromCurve" << stabBank->getName();
UAVObjectField *field = stabBank->getField("ThrustPIDScaleCurve");
Q_ASSERT(field);
@ -222,7 +219,6 @@ void ConfigStabilizationWidget::updateObjectFromThrottleCurve()
QList<double> curve = ui->thrustPIDScalingCurve->getCurve();
for (quint32 i = 0; i < field->getNumElements(); i++) {
field->setValue(curve.at(i), i);
qDebug() << field->getName() << field->getElementNames().at(i) << "<=" << curve.at(i);
}
field = stabBank->getField("EnableThrustPIDScaling");
@ -351,10 +347,8 @@ void ConfigStabilizationWidget::realtimeUpdatesSlot(bool value)
if (value && !realtimeUpdates->isActive()) {
realtimeUpdates->start(AUTOMATIC_UPDATE_RATE);
qDebug() << "Instant Update timer started.";
} else if (!value && realtimeUpdates->isActive()) {
realtimeUpdates->stop();
qDebug() << "Instant Update timer stopped.";
}
}
@ -451,7 +445,6 @@ void ConfigStabilizationWidget::pidBankChanged(int index)
setWidgetBindingObjectEnabled(m_pidTabBars.at(0)->tabData(index).toString(), true);
m_currentPIDBank = index;
qDebug() << "current bank:" << m_currentPIDBank;
updateThrottleCurveFromObject();
setDirty(dirty);
}

View File

@ -47,8 +47,8 @@ MagicWaypointGadgetWidget::MagicWaypointGadgetWidget(QWidget *parent) : QLabel(p
m_magicwaypoint->setupUi(this);
// Connect object updated event from UAVObject to also update check boxes
connect(getPathDesired(), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(positionObjectChanged(UAVObject *)));
connect(getPositionState(), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(positionObjectChanged(UAVObject *)));
connect(getPathDesired(), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(positionStateChanged(UAVObject *)));
connect(getPositionState(), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(positionStateChanged(UAVObject *)));
// Connect updates from the position widget to this widget
connect(m_magicwaypoint->widgetPosition, SIGNAL(positionClicked(double, double)), this, SLOT(positionSelected(double, double)));

View File

@ -0,0 +1,62 @@
<html>
<head></head>
<body style="font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
<table width='100%' cellpadding="5">
<tr bgcolor='#308BC6'>
<td rowspan='1' colspan='4'><b>{{OBJECT_NAME_TITLE}}:&nbsp;</b>{{OBJECT_NAME}}</td>
</tr>
<tr>
<td colspan='1'><b>{{CATEGORY_TITLE}}:&nbsp;</b>{{CATEGORY}}</td>
<td colspan='1'><b>{{TYPE_TITLE}}:&nbsp;</b>{{TYPE}}</td>
<td colspan='1'><b>{{SIZE_TITLE}}:&nbsp;</b>{{SIZE}}&nbsp;bytes</td>
<td colspan='1'><b>{{MULTI_INSTANCE_TITLE}}:&nbsp;</b>{{MULTI_INSTANCE}}</td>
</tr>
<tr>
<td colspan='4' rowspan='1' valign='top'><b>{{DESCRIPTION_TITLE}}:&nbsp;</b>{{DESCRIPTION}}</td>
<tr bgcolor='#51A0D3'>
<td rowspan='1' colspan='4'><b>{{FIELDS_NAME_TITLE}}</td>
</tr>
{{#FIELDS}}
<tr>
<td colspan='4'>
<table width='100%' cellpadding="5">
<tr bgcolor='#7DBAE2'>
<td rowspan='1' colspan='4'><b>{{FIELD_NAME_TITLE}}:&nbsp;</b>{{FIELD_NAME}}</td>
</tr>
<tr>
<td rowspan='1' colspan='1'><b>{{FIELD_TYPE_TITLE}}:&nbsp;</b>{{FIELD_TYPE}}</td>
{{#FIELD_UNIT_TITLE}}
<td rowspan='1' colspan='2'><b>{{FIELD_UNIT_TITLE}}:&nbsp;</b>{{FIELD_UNIT}}</td>
{{/FIELD_UNIT_TITLE}}
</tr>
{{#FIELD_OPTIONS_TITLE}}
<tr>
<td rowspan='1' colspan='2'><b>{{FIELD_OPTIONS_TITLE}}:&nbsp;
</b>{{#FIELD_OPTIONS}}{{FIELD_OPTION_DELIM}}{{FIELD_OPTION}}{{/FIELD_OPTIONS}}</td>
</tr>
{{/FIELD_OPTIONS_TITLE}}
{{#FIELD_ELEMENTS_TITLE}}
<tr>
<td rowspan='1' colspan='2'><b>{{FIELD_ELEMENTS_TITLE}}:&nbsp;
</b>{{#FIELD_ELEMENTS}}{{FIELD_ELEMENT_DELIM}}{{FIELD_ELEMENT}}{{FIELD_ELEMENT_LIMIT}}{{/FIELD_ELEMENTS}}</td>
</tr>
{{/FIELD_ELEMENTS_TITLE}}
{{^FIELD_ELEMENTS_TITLE}}
{{#FIELD_LIMIT_TITLE}}
<tr>
<td rowspan='1' colspan='2'><b>{{FIELD_LIMIT_TITLE}}:&nbsp;</b>{{FIELD_LIMIT}}</td>
</tr>
{{/FIELD_LIMIT_TITLE}}
{{/FIELD_ELEMENTS_TITLE}}
{{#FIELD_DESCRIPTION_TITLE}}
<tr>
<td rowspan='1' colspan='2'><b>{{FIELD_DESCRIPTION_TITLE}}:&nbsp;</b>{{FIELD_DESCRIPTION}}</td>
</tr>
{{/FIELD_DESCRIPTION_TITLE}}
</table>
</td>
</tr>
{{/FIELDS}}
</table>
</body>
</html>

View File

@ -32,7 +32,8 @@ UAVObjectBrowser::UAVObjectBrowser(QString classId, UAVObjectBrowserWidget *widg
m_widget(widget),
m_config(NULL)
{
connect(m_widget, SIGNAL(viewOptionsChanged(bool, bool, bool)), this, SLOT(viewOptionsChangedSlot(bool, bool, bool)));
connect(m_widget, SIGNAL(viewOptionsChanged(bool, bool, bool, bool)), this, SLOT(viewOptionsChangedSlot(bool, bool, bool, bool)));
connect(m_widget, SIGNAL(splitterChanged(QByteArray)), this, SLOT(splitterChanged(QByteArray)));
}
UAVObjectBrowser::~UAVObjectBrowser()
@ -50,14 +51,23 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config)
m_widget->setManuallyChangedColor(m->manuallyChangedColor());
m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout());
m_widget->setOnlyHilightChangedValues(m->onlyHighlightChangedValues());
m_widget->setViewOptions(m->categorizedView(), m->scientificView(), m->showMetaData());
m_widget->setViewOptions(m->categorizedView(), m->scientificView(), m->showMetaData(), m->showDescription());
m_widget->setSplitterState(m->splitterState());
}
void UAVObjectBrowser::viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata)
void UAVObjectBrowser::viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description)
{
if (m_config) {
m_config->setCategorizedView(categorized);
m_config->setScientificView(scientific);
m_config->setShowMetaData(metadata);
m_config->setShowDescription(description);
}
}
void UAVObjectBrowser::splitterChanged(QByteArray state)
{
if (m_config) {
m_config->setSplitterState(state);
}
}

View File

@ -50,8 +50,11 @@ public:
return m_widget;
}
void loadConfiguration(IUAVGadgetConfiguration *config);
private slots:
void viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata);
void viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description);
void splitterChanged(QByteArray state);
private:
UAVObjectBrowserWidget *m_widget;
UAVObjectBrowserConfiguration *m_config;

View File

@ -6,5 +6,6 @@
<file>images/up_alt.png</file>
<file>images/trash.png</file>
<file>images/1343241276_eye.png</file>
<file>resources/uavodescription.mustache</file>
</qresource>
</RCC>

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>786</width>
<height>300</height>
<height>462</height>
</rect>
</property>
<property name="windowTitle">
@ -220,7 +220,63 @@
</layout>
</item>
<item>
<widget class="QTreeView" name="treeView"/>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="lineWidth">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeView" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QTextEdit" name="descriptionText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>150</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
<property name="placeholderText">
<string>This space shows a description of the selected UAVObject.</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>

View File

@ -36,23 +36,21 @@ UAVObjectBrowserConfiguration::UAVObjectBrowserConfiguration(QString classId, QS
m_recentlyUpdatedTimeout(500),
m_useCategorizedView(false),
m_useScientificView(false),
m_showMetaData(false)
m_showMetaData(false),
m_showDescription(false)
{
// if a saved configuration exists load it
if (qSettings != 0) {
QColor recent = qSettings->value("recentlyUpdatedColor").value<QColor>();
QColor manual = qSettings->value("manuallyChangedColor").value<QColor>();
int timeout = qSettings->value("recentlyUpdatedTimeout").toInt();
bool hilight = qSettings->value("onlyHilightChangedValues").toBool();
m_unknownObjectColor = qSettings->value("unknownObjectColor", QVariant(QColor(Qt::gray))).value<QColor>();
m_useCategorizedView = qSettings->value("CategorizedView").toBool();
m_useScientificView = qSettings->value("ScientificView").toBool();
m_showMetaData = qSettings->value("showMetaData").toBool();
m_recentlyUpdatedColor = recent;
m_manuallyChangedColor = manual;
m_recentlyUpdatedTimeout = timeout;
m_onlyHilightChangedValues = hilight;
m_showDescription = qSettings->value("showDescription").toBool();
m_splitterState = qSettings->value("splitterState").toByteArray();
m_recentlyUpdatedColor = qSettings->value("recentlyUpdatedColor").value<QColor>();
m_manuallyChangedColor = qSettings->value("manuallyChangedColor").value<QColor>();
m_recentlyUpdatedTimeout = qSettings->value("recentlyUpdatedTimeout").toInt();
m_onlyHilightChangedValues = qSettings->value("onlyHilightChangedValues").toBool();
}
}
@ -66,8 +64,10 @@ IUAVGadgetConfiguration *UAVObjectBrowserConfiguration::clone()
m->m_onlyHilightChangedValues = m_onlyHilightChangedValues;
m->m_useCategorizedView = m_useCategorizedView;
m->m_useScientificView = m_useScientificView;
m->m_splitterState = m_splitterState;
m->m_showMetaData = m_showMetaData;
m->m_unknownObjectColor = m_unknownObjectColor;
m->m_showDescription = m_showDescription;
return m;
}
@ -85,4 +85,6 @@ void UAVObjectBrowserConfiguration::saveConfig(QSettings *qSettings) const
qSettings->setValue("CategorizedView", m_useCategorizedView);
qSettings->setValue("ScientificView", m_useScientificView);
qSettings->setValue("showMetaData", m_showMetaData);
qSettings->setValue("showDescription", m_showDescription);
qSettings->setValue("splitterState", m_splitterState);
}

View File

@ -41,7 +41,9 @@ class UAVObjectBrowserConfiguration : public IUAVGadgetConfiguration {
Q_PROPERTY(bool m_onlyHilightChangedValues READ onlyHighlightChangedValues WRITE setOnlyHighlightChangedValues)
Q_PROPERTY(bool m_useCategorizedView READ categorizedView WRITE setCategorizedView)
Q_PROPERTY(bool m_useScientificView READ scientificView WRITE setScientificView)
Q_PROPERTY(bool m_showDescription READ showDescription WRITE setShowDescription)
Q_PROPERTY(bool m_showMetaData READ showMetaData WRITE setShowMetaData)
Q_PROPERTY(QByteArray m_splitterState READ splitterState WRITE setSplitterState)
public:
explicit UAVObjectBrowserConfiguration(QString classId, QSettings *qSettings = 0, QObject *parent = 0);
@ -80,6 +82,15 @@ public:
{
return m_showMetaData;
}
bool showDescription() const
{
return m_showDescription;
}
QByteArray splitterState() const
{
return m_splitterState;
}
signals:
@ -116,6 +127,15 @@ public slots:
{
m_showMetaData = value;
}
void setShowDescription(bool value)
{
m_showDescription = value;
}
void setSplitterState(QByteArray arg)
{
m_splitterState = arg;
}
private:
QColor m_unknownObjectColor;
@ -126,6 +146,8 @@ private:
bool m_useCategorizedView;
bool m_useScientificView;
bool m_showMetaData;
bool m_showDescription;
QByteArray m_splitterState;
};
#endif // UAVOBJECTBROWSERCONFIGURATION_H

View File

@ -39,6 +39,7 @@
#include <QtCore/QDebug>
#include <QItemEditorFactory>
#include "extensionsystem/pluginmanager.h"
#include "utils/mustache.h"
UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent)
{
@ -55,12 +56,14 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent
m_browser->treeView->setItemDelegate(m_delegate);
m_browser->treeView->setEditTriggers(QAbstractItemView::AllEditTriggers);
m_browser->treeView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_mustacheTemplate = loadFileIntoString(QString(":/uavobjectbrowser/resources/uavodescription.mustache"));
showMetaData(m_viewoptions->cbMetaData->isChecked());
connect(m_browser->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)), Qt::UniqueConnection);
showDescription(m_viewoptions->cbDescription->isChecked());
connect(m_browser->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
this, SLOT(currentChanged(QModelIndex, QModelIndex)), Qt::UniqueConnection);
connect(m_viewoptions->cbMetaData, SIGNAL(toggled(bool)), this, SLOT(showMetaData(bool)));
connect(m_viewoptions->cbCategorized, SIGNAL(toggled(bool)), this, SLOT(categorize(bool)));
connect(m_viewoptions->cbDescription, SIGNAL(toggled(bool)), this, SLOT(showDescription(bool)));
connect(m_browser->saveSDButton, SIGNAL(clicked()), this, SLOT(saveObject()));
connect(m_browser->readSDButton, SIGNAL(clicked()), this, SLOT(loadObject()));
connect(m_browser->eraseSDButton, SIGNAL(clicked()), this, SLOT(eraseObject()));
@ -71,7 +74,8 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent
connect(m_viewoptions->cbScientific, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot()));
connect(m_viewoptions->cbMetaData, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot()));
connect(m_viewoptions->cbCategorized, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot()));
connect(m_viewoptions->cbDescription, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot()));
connect(m_browser->splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved()));
enableSendRequest(false);
}
@ -80,11 +84,17 @@ UAVObjectBrowserWidget::~UAVObjectBrowserWidget()
delete m_browser;
}
void UAVObjectBrowserWidget::setViewOptions(bool categorized, bool scientific, bool metadata)
void UAVObjectBrowserWidget::setViewOptions(bool categorized, bool scientific, bool metadata, bool description)
{
m_viewoptions->cbCategorized->setChecked(categorized);
m_viewoptions->cbMetaData->setChecked(metadata);
m_viewoptions->cbScientific->setChecked(scientific);
m_viewoptions->cbDescription->setChecked(description);
}
void UAVObjectBrowserWidget::setSplitterState(QByteArray state)
{
m_browser->splitter->restoreState(state);
}
void UAVObjectBrowserWidget::showMetaData(bool show)
@ -95,6 +105,11 @@ void UAVObjectBrowserWidget::showMetaData(bool show)
}
}
void UAVObjectBrowserWidget::showDescription(bool show)
{
m_browser->descriptionText->setVisible(show);
}
void UAVObjectBrowserWidget::categorize(bool categorize)
{
UAVObjectTreeModel *tmpModel = m_model;
@ -165,6 +180,17 @@ ObjectTreeItem *UAVObjectBrowserWidget::findCurrentObjectTreeItem()
return objItem;
}
QString UAVObjectBrowserWidget::loadFileIntoString(QString fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QTextStream stream(&file);
QString line = stream.readAll();
file.close();
return line;
}
void UAVObjectBrowserWidget::saveObject()
{
this->setFocus();
@ -233,6 +259,7 @@ void UAVObjectBrowserWidget::currentChanged(const QModelIndex &current, const QM
enable = false;
}
enableSendRequest(enable);
updateDescription();
}
void UAVObjectBrowserWidget::viewSlot()
@ -249,7 +276,94 @@ void UAVObjectBrowserWidget::viewSlot()
void UAVObjectBrowserWidget::viewOptionsChangedSlot()
{
emit viewOptionsChanged(m_viewoptions->cbCategorized->isChecked(), m_viewoptions->cbScientific->isChecked(), m_viewoptions->cbMetaData->isChecked());
emit viewOptionsChanged(m_viewoptions->cbCategorized->isChecked(), m_viewoptions->cbScientific->isChecked(),
m_viewoptions->cbMetaData->isChecked(), m_viewoptions->cbDescription->isChecked());
}
void UAVObjectBrowserWidget::splitterMoved()
{
emit splitterChanged(m_browser->splitter->saveState());
}
QString UAVObjectBrowserWidget::createObjectDescription(UAVObject *object)
{
QString mustache(m_mustacheTemplate);
QVariantHash uavoHash;
uavoHash["OBJECT_NAME_TITLE"] = tr("Name");
uavoHash["OBJECT_NAME"] = object->getName();
uavoHash["CATEGORY_TITLE"] = tr("Category");
uavoHash["CATEGORY"] = object->getCategory();
uavoHash["TYPE_TITLE"] = tr("Type");
uavoHash["TYPE"] = object->isMetaDataObject() ? tr("Metadata") : object->isSettingsObject() ? tr("Setting") : tr("Data");
uavoHash["SIZE_TITLE"] = tr("Size");
uavoHash["SIZE"] = object->getNumBytes();
uavoHash["DESCRIPTION_TITLE"] = tr("Description");
uavoHash["DESCRIPTION"] = object->getDescription().replace("@ref", "");
uavoHash["MULTI_INSTANCE_TITLE"] = tr("Multi");
uavoHash["MULTI_INSTANCE"] = object->isSingleInstance() ? tr("No") : tr("Yes");
uavoHash["FIELDS_NAME_TITLE"] = tr("Fields");
QVariantList fields;
foreach(UAVObjectField * field, object->getFields()) {
QVariantHash fieldHash;
fieldHash["FIELD_NAME_TITLE"] = tr("Name");
fieldHash["FIELD_NAME"] = field->getName();
fieldHash["FIELD_TYPE_TITLE"] = tr("Type");
fieldHash["FIELD_TYPE"] = QString("%1%2").arg(field->getTypeAsString(),
(field->getNumElements() > 1 ? QString("[%1]").arg(field->getNumElements()) : QString()));
if (!field->getUnits().isEmpty()) {
fieldHash["FIELD_UNIT_TITLE"] = tr("Unit");
fieldHash["FIELD_UNIT"] = field->getUnits();
}
if (!field->getOptions().isEmpty()) {
fieldHash["FIELD_OPTIONS_TITLE"] = tr("Options");
QVariantList options;
foreach(QString option, field->getOptions()) {
QVariantHash optionHash;
optionHash["FIELD_OPTION"] = option;
if (!options.isEmpty()) {
optionHash["FIELD_OPTION_DELIM"] = ", ";
}
options.append(optionHash);
}
fieldHash["FIELD_OPTIONS"] = options;
}
if (field->getElementNames().count() > 1) {
fieldHash["FIELD_ELEMENTS_TITLE"] = tr("Elements");
QVariantList elements;
for (int i = 0; i < field->getElementNames().count(); i++) {
QString element = field->getElementNames().at(i);
QVariantHash elementHash;
elementHash["FIELD_ELEMENT"] = element;
QString limitsString = field->getLimitsAsString(i);
if (!limitsString.isEmpty()) {
elementHash["FIELD_ELEMENT_LIMIT"] = limitsString.prepend(" (").append(")");
}
if (!elements.isEmpty()) {
elementHash["FIELD_ELEMENT_DELIM"] = ", ";
}
elements.append(elementHash);
}
fieldHash["FIELD_ELEMENTS"] = elements;
} else if (!field->getLimitsAsString(0).isEmpty()) {
fieldHash["FIELD_LIMIT_TITLE"] = tr("Limits");
fieldHash["FIELD_LIMIT"] = field->getLimitsAsString(0);
}
if (!field->getDescription().isEmpty()) {
fieldHash["FIELD_DESCRIPTION_TITLE"] = tr("Description");
fieldHash["FIELD_DESCRIPTION"] = field->getDescription();
}
fields.append(fieldHash);
}
uavoHash["FIELDS"] = fields;
Mustache::QtVariantContext context(uavoHash);
Mustache::Renderer renderer;
return renderer.render(mustache, &context);
}
void UAVObjectBrowserWidget::enableSendRequest(bool enable)
@ -260,3 +374,17 @@ void UAVObjectBrowserWidget::enableSendRequest(bool enable)
m_browser->readSDButton->setEnabled(enable);
m_browser->eraseSDButton->setEnabled(enable);
}
void UAVObjectBrowserWidget::updateDescription()
{
ObjectTreeItem *objItem = findCurrentObjectTreeItem();
if (objItem) {
UAVObject *obj = objItem->object();
if (obj) {
m_browser->descriptionText->setText(createObjectDescription(obj));
return;
}
}
m_browser->descriptionText->setText("");
}

View File

@ -70,9 +70,11 @@ public:
m_onlyHilightChangedValues = hilight;
m_model->setOnlyHilightChangedValues(hilight);
}
void setViewOptions(bool categorized, bool scientific, bool metadata);
void setViewOptions(bool categorized, bool scientific, bool metadata, bool description);
void setSplitterState(QByteArray state);
public slots:
void showMetaData(bool show);
void showDescription(bool show);
void categorize(bool categorize);
void useScientificNotation(bool scientific);
@ -85,10 +87,11 @@ private slots:
void currentChanged(const QModelIndex &current, const QModelIndex &previous);
void viewSlot();
void viewOptionsChangedSlot();
void splitterMoved();
QString createObjectDescription(UAVObject *object);
signals:
void viewOptionsChanged(bool categorized, bool scientific, bool metadata);
void viewOptionsChanged(bool categorized, bool scientific, bool metadata, bool description);
void splitterChanged(QByteArray state);
private:
QPushButton *m_requestUpdate;
QPushButton *m_sendUpdate;
@ -102,10 +105,13 @@ private:
QColor m_recentlyUpdatedColor;
QColor m_manuallyChangedColor;
bool m_onlyHilightChangedValues;
QString m_mustacheTemplate;
void updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj);
void enableSendRequest(bool enable);
void updateDescription();
ObjectTreeItem *findCurrentObjectTreeItem();
QString loadFileIntoString(QString fileName);
};
#endif /* UAVOBJECTBROWSERWIDGET_H_ */

View File

@ -256,6 +256,7 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt
Q_ASSERT(false);
}
item->setHighlightManager(m_highlightManager);
item->setDescription(field->getDescription());
connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *)));
parent->appendChild(item);
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>169</width>
<height>96</height>
<width>172</width>
<height>124</height>
</rect>
</property>
<property name="windowTitle">
@ -35,6 +35,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbDescription">
<property name="text">
<string>Show Description</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -41,10 +41,10 @@ UAVMetaObject::UAVMetaObject(quint32 objID, const QString & name, UAVObject *par
QStringList modesBitField;
modesBitField << tr("FlightReadOnly") << tr("GCSReadOnly") << tr("FlightTelemetryAcked") << tr("GCSTelemetryAcked") << tr("FlightUpdatePeriodic") << tr("FlightUpdateOnChange") << tr("GCSUpdatePeriodic") << tr("GCSUpdateOnChange") << tr("LoggingUpdatePeriodic") << tr("LoggingUpdateOnChange");
QList<UAVObjectField *> fields;
fields.append(new UAVObjectField(tr("Modes"), tr("boolean"), UAVObjectField::BITFIELD, modesBitField, QStringList()));
fields.append(new UAVObjectField(tr("Flight Telemetry Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
fields.append(new UAVObjectField(tr("GCS Telemetry Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
fields.append(new UAVObjectField(tr("Logging Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
fields.append(new UAVObjectField(tr("Modes"), tr("Metadata modes"), tr("boolean"), UAVObjectField::BITFIELD, modesBitField, QStringList()));
fields.append(new UAVObjectField(tr("Flight Telemetry Update Period"), tr("This is how often flight side will update telemetry data"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
fields.append(new UAVObjectField(tr("GCS Telemetry Update Period"), tr("This is how often GCS will update telemetry data"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
fields.append(new UAVObjectField(tr("Logging Update Period"), tr("This is how often logging will be updated."), tr("ms"), UAVObjectField::UINT16, 1, QStringList()));
// Initialize parent
UAVObject::initialize(0);
UAVObject::initializeFields(fields, (quint8 *)&parentMetadata, sizeof(Metadata));

View File

@ -30,7 +30,7 @@
#include <QDebug>
#include <QtWidgets>
UAVObjectField::UAVObjectField(const QString & name, const QString & units, FieldType type, quint32 numElements, const QStringList & options, const QString &limits)
UAVObjectField::UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, quint32 numElements, const QStringList & options, const QString &limits)
{
QStringList elementNames;
@ -39,18 +39,19 @@ UAVObjectField::UAVObjectField(const QString & name, const QString & units, Fiel
elementNames.append(QString("%1").arg(n));
}
// Initialize
constructorInitialize(name, units, type, elementNames, options, limits);
constructorInitialize(name, description, units, type, elementNames, options, limits);
}
UAVObjectField::UAVObjectField(const QString & name, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
UAVObjectField::UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
{
constructorInitialize(name, units, type, elementNames, options, limits);
constructorInitialize(name, description, units, type, elementNames, options, limits);
}
void UAVObjectField::constructorInitialize(const QString & name, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
void UAVObjectField::constructorInitialize(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
{
// Copy params
this->name = name;
this->description = description;
this->units = units;
this->type = type;
this->options = options;
@ -458,11 +459,65 @@ bool UAVObjectField::isWithinLimits(QVariant var, quint32 index, int board)
default:
return true;
}
default:
return true;
}
}
return true;
}
QString UAVObjectField::getLimitsAsString(quint32 index, int board)
{
QString limitString;
if (elementLimits.keys().contains(index)) {
foreach(LimitStruct struc, elementLimits.value(index)) {
if ((struc.board != board) && board != 0 && struc.board != 0) {
continue;
}
switch (struc.type) {
case EQUAL:
{
limitString.append(tr("one of")).append(" [");
bool first = true;
foreach(QVariant var, struc.values) {
if (!first) {
limitString.append(", ");
}
limitString.append(var.toString());
first = false;
}
return limitString.append("]");
}
case NOT_EQUAL:
{
limitString.append(tr("none of")).append(" [");
bool first = true;
foreach(QVariant var, struc.values) {
if (!first) {
limitString.append(", ");
}
limitString.append(var.toString());
first = false;
}
return limitString.append("]");
}
case BIGGER: return limitString.append(QString("%1 %2").arg(tr("more than"), struc.values.at(0).toString()));
case BETWEEN: return limitString.append(QString("%1 %2 %3 %4")
.arg(tr("between"), struc.values.at(0).toString(),
tr(" and "), struc.values.at(1).toString()));
case SMALLER: return limitString.append(QString("%1 %2").arg(tr("less than"), struc.values.at(0).toString()));
default:
break;
}
}
}
return limitString;
}
QVariant UAVObjectField::getMaxLimit(quint32 index, int board)
{
if (!elementLimits.keys().contains(index)) {
@ -478,20 +533,14 @@ QVariant UAVObjectField::getMaxLimit(quint32 index, int board)
case BIGGER:
return QVariant();
break;
break;
case BETWEEN:
return struc.values.at(1);
break;
case SMALLER:
return struc.values.at(0);
break;
default:
return QVariant();
break;
}
}
return QVariant();
@ -511,20 +560,14 @@ QVariant UAVObjectField::getMinLimit(quint32 index, int board)
case SMALLER:
return QVariant();
break;
break;
case BETWEEN:
return struc.values.at(0);
break;
case BIGGER:
return struc.values.at(0);
break;
default:
return QVariant();
break;
}
}
return QVariant();
@ -609,6 +652,11 @@ QString UAVObjectField::getName()
return name;
}
QString UAVObjectField::getDescription()
{
return description;
}
QString UAVObjectField::getUnits()
{
return units;

View File

@ -45,20 +45,21 @@ class UAVOBJECTS_EXPORT UAVObjectField : public QObject {
public:
typedef enum { INT8 = 0, INT16, INT32, UINT8, UINT16, UINT32, FLOAT32, ENUM, BITFIELD, STRING } FieldType;
typedef enum { EQUAL, NOT_EQUAL, BETWEEN, BIGGER, SMALLER } LimitType;
typedef enum { EQUAL, NOT_EQUAL, BETWEEN, BIGGER, SMALLER, UNDEFINED } LimitType;
typedef struct {
LimitType type;
QList<QVariant> values;
int board;
} LimitStruct;
UAVObjectField(const QString & name, const QString & units, FieldType type, quint32 numElements, const QStringList & options, const QString & limits = QString());
UAVObjectField(const QString & name, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString & limits = QString());
UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, quint32 numElements, const QStringList & options, const QString & limits = QString());
UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString & limits = QString());
void initialize(quint8 *data, quint32 dataOffset, UAVObject *obj);
UAVObject *getObject();
FieldType getType();
QString getTypeAsString();
QString getName();
QString getDescription();
QString getUnits();
quint32 getNumElements();
QStringList getElementNames();
@ -84,6 +85,7 @@ public:
void fromJson(const QJsonObject &jsonObject);
bool isWithinLimits(QVariant var, quint32 index, int board = 0);
QString getLimitsAsString(quint32 index, int board = 0);
QVariant getMaxLimit(quint32 index, int board = 0);
QVariant getMinLimit(quint32 index, int board = 0);
signals:
@ -91,6 +93,7 @@ signals:
protected:
QString name;
QString description;
QString units;
FieldType type;
QStringList elementNames;
@ -102,7 +105,7 @@ protected:
UAVObject *obj;
QMap<quint32, QList<LimitStruct> > elementLimits;
void clear();
void constructorInitialize(const QString & name, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits);
void constructorInitialize(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits);
void limitsInitialize(const QString &limits);
};

View File

@ -10,8 +10,6 @@ Rectangle {
sourceComponent: scrollDecorator.flickableItem ? scrollBar : undefined
}
Component.onDestruction: scrollLoader.sourceComponent = undefined
Component {
id: scrollBar
Rectangle {

View File

@ -259,8 +259,9 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *info)
.arg(varOptionName)
.arg(options[m]));
}
finit.append(QString(" fields.append( new UAVObjectField(QString(\"%1\"), QString(\"%2\"), UAVObjectField::ENUM, %3, %4, QString(\"%5\")));\n")
finit.append(QString(" fields.append( new UAVObjectField(QString(\"%1\"), tr(\"%2\"), QString(\"%3\"), UAVObjectField::ENUM, %4, %5, QString(\"%6\")));\n")
.arg(info->fields[n]->name)
.arg(info->fields[n]->description)
.arg(info->fields[n]->units)
.arg(varElemName)
.arg(varOptionName)
@ -268,8 +269,9 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *info)
}
// For all other types
else {
finit.append(QString(" fields.append( new UAVObjectField(QString(\"%1\"), QString(\"%2\"), UAVObjectField::%3, %4, QStringList(), QString(\"%5\")));\n")
finit.append(QString(" fields.append( new UAVObjectField(QString(\"%1\"), tr(\"%2\"), QString(\"%3\"), UAVObjectField::%4, %5, QStringList(), QString(\"%6\")));\n")
.arg(info->fields[n]->name)
.arg(info->fields[n]->description)
.arg(info->fields[n]->units)
.arg(fieldTypeStrCPPClass[info->fields[n]->type])
.arg(varElemName)

View File

@ -25,7 +25,7 @@
*/
#include "uavobjectparser.h"
#include <QDebug>
/**
* Constructor
*/
@ -441,6 +441,21 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
field->name = name;
}
// Get description attribute if any
elemAttr = elemAttributes.namedItem("description");
if (!elemAttr.isNull()) {
field->description = elemAttr.nodeValue();
} else {
// Look for a child description node
QDomNode node = childNode.firstChildElement("description");
if (!node.isNull()) {
QDomNode description = node.firstChild();
if (!description.isNull()) {
field->description = description.nodeValue();
}
}
}
// Get units attribute
elemAttr = elemAttributes.namedItem("units");
if (elemAttr.isNull()) {

View File

@ -49,6 +49,7 @@ typedef enum {
typedef struct {
QString name;
QString description;
QString units;
FieldType type;
int numElements;

View File

@ -1,6 +1,6 @@
<xml>
<object name="CameraStabSettings" singleinstance="true" settings="true" category="Control">
<description>Settings for the @ref CameraStab mmodule</description>
<description>Settings for the @ref CameraStab module</description>
<field name="Input" units="channel" type="enum" elementnames="Roll,Pitch,Yaw" options="Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5,None" defaultvalue="None"/>
<field name="InputRange" units="deg" type="uint8" elementnames="Roll,Pitch,Yaw" defaultvalue="20"/>
<field name="InputRate" units="deg/s" type="uint8" elementnames="Roll,Pitch,Yaw" defaultvalue="50"/>

View File

@ -1,7 +1,10 @@
<xml>
<object name="DebugLogSettings" singleinstance="true" settings="true" category="System">
<description>Configure On Board Logging Facilities</description>
<field name="LoggingEnabled" units="" type="enum" elements="1" options="Disabled,OnlyWhenArmed,Always" defaultvalue="Disabled" />
<field name="LoggingEnabled" units="" type="enum" elements="1" options="Disabled,OnlyWhenArmed,Always" defaultvalue="Disabled">
<description>If set to OnlyWhenArmed logs will only be saved when craft is armed. Disabled turns logging off, and Always will always log.</description>
</field>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>

View File

@ -1,10 +1,10 @@
<xml>
<object name="DebugLogStatus" singleinstance="true" settings="false" category="System">
<description>Log Status Object, contains log partition status information</description>
<field name="Flight" units="" type="uint16" elements="1" />
<field name="Entry" units="" type="uint16" elements="1" />
<field name="UsedSlots" units="" type="uint16" elements="1" />
<field name="FreeSlots" units="" type="uint16" elements="1" />
<field name="Flight" units="" type="uint16" elements="1" description="The current flight number (logging session)"/>
<field name="Entry" units="" type="uint16" elements="1" description="The current log entry id"/>
<field name="UsedSlots" units="" type="uint16" elements="1" description="Holds the total log entries saved"/>
<field name="FreeSlots" units="" type="uint16" elements="1" description="The number of free log slots available"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>

View File

@ -1,6 +1,6 @@
<xml>
<object name="HomeLocation" singleinstance="true" settings="true" category="Navigation">
<description>HomeLocation setting which contains the constants to tranlate from longitutde and latitude to NED reference frame. Automatically set by @ref GPSModule after acquiring a 3D lock. Used by @ref AHRSCommsModule.</description>
<description>HomeLocation setting which contains the constants to translate from longitude and latitude to NED reference frame. Automatically set by @ref GPSModule after acquiring a 3D lock. Used by @ref AHRSCommsModule.</description>
<field name="Set" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE"/>
<field name="Latitude" units="deg * 10e6" type="int32" elements="1" defaultvalue="0"/>
<field name="Longitude" units="deg * 10e6" type="int32" elements="1" defaultvalue="0"/>

View File

@ -1,6 +1,6 @@
<xml>
<object name="ManualControlCommand" singleinstance="true" settings="false" category="Control">
<description>The output from the @ref ManualControlModule which descodes the receiver inputs. Overriden by GCS for fly-by-wire control.</description>
<description>The output from the @ref ManualControlModule which decodes the receiver inputs. Overriden by GCS for fly-by-wire control.</description>
<field name="Connected" units="" type="enum" elements="1" options="False,True"/>
<field name="Throttle" units="%" type="float" elements="1"/>
<field name="Roll" units="%" type="float" elements="1"/>