diff --git a/.vscode/settings.json b/.vscode/settings.json index 1e4a5cb51a682ae308bb4bc66aa04bc5dded9a33..418de16bdb77a6fe9e3032f6f2dc1a65c8d6d814 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -93,7 +93,8 @@ "qpair": "cpp", "qstring": "cpp", "qregularexpression": "cpp", - "qmessagebox": "cpp" + "qmessagebox": "cpp", + "regex": "cpp" }, "editor.defaultFormatter": "chiehyu.vscode-astyle", "[xml]": { diff --git a/Core/xmlobject.cpp b/Core/xmlobject.cpp index 2c6692e767e4c6942246e5ed7b3cf79192450b66..e452463fcd42b93d2894a469c891a2af88bf9d91 100644 --- a/Core/xmlobject.cpp +++ b/Core/xmlobject.cpp @@ -1,22 +1,21 @@ #include "xmlobject.h" -#include <QTextStream> #include <QFile> +#include <QTextStream> -XmlObject::XmlObject(const QString& objectName) { - setObjectName(objectName); -} +XmlObject::XmlObject(const QString& objectName) { setObjectName(objectName); } -XmlObject::XmlObject(const XmlObject& other) { - copy(other); -} +XmlObject::XmlObject(const XmlObject& other) { copy(other); } -bool XmlObject::loadFromFile(const QString& filePath) { +bool XmlObject::loadFromFile(const QString& filePath) +{ bool result = false; QFile file(filePath); - if(file.exists() && file.open(QIODevice::ReadOnly)) { + if (file.exists() && file.open(QIODevice::ReadOnly)) + { QString msgDefFileContent = QTextStream(&file).readAll(); - if(msgDefFileContent != "") { + if (msgDefFileContent != "") + { this->fromXml(msgDefFileContent); result = true; } @@ -25,10 +24,12 @@ bool XmlObject::loadFromFile(const QString& filePath) { return result; } -bool XmlObject::writeToFile(const QString& filePath, const QString& codec) const { +bool XmlObject::writeToFile(const QString& filePath, const QString& codec) const +{ bool result = false; QFile file(filePath); - if(file.open(QIODevice::WriteOnly)) { + if (file.open(QIODevice::WriteOnly)) + { QTextStream textStream(&file); textStream.setCodec(codec.toUtf8()); textStream << this->toXml(); @@ -38,7 +39,8 @@ bool XmlObject::writeToFile(const QString& filePath, const QString& codec) const return result; } -QString XmlObject::toXml() const { +QString XmlObject::toXml() const +{ QString output; QXmlStreamWriter xWriter(&output); xWriter.setAutoFormatting(true); @@ -46,93 +48,108 @@ QString XmlObject::toXml() const { return output; } - -void XmlObject::toXml(QXmlStreamWriter* xmlWriter) const { +void XmlObject::toXml(QXmlStreamWriter* xmlWriter) const +{ xmlWriter->writeStartElement(xmlObjectName); - for(QString key : attributes.keys()) { + for (QString key : attributes.keys()) + { xmlWriter->writeAttribute(key, attributes[key]); } - if(getTextValue() != "" && childCount() == 0) { + if (getTextValue() != "" && childCount() == 0) + { xmlWriter->writeCharacters(getTextValue()); } - for(XmlObject c : childList) { + for (XmlObject c : childList) + { c.toXml(xmlWriter); } xmlWriter->writeEndElement(); } -void XmlObject::fromXml(const QString& txt) { +void XmlObject::fromXml(const QString& txt) +{ QXmlStreamReader xReader(txt); xReader.readNextStartElement(); fromXml(&xReader); } -void XmlObject::fromXml(QXmlStreamReader* xmlReader) { +void XmlObject::fromXml(QXmlStreamReader* xmlReader) +{ childList.clear(); attributes.clear(); - if(xmlReader->isStartElement()) { + if (xmlReader->isStartElement()) + { setObjectName(xmlReader->name().toString()); - for(auto attr : xmlReader->attributes()) { + for (auto attr : xmlReader->attributes()) + { attributes[attr.name().toString()] = attr.value().toString(); } } - while(!xmlReader->atEnd()) { + while (!xmlReader->atEnd()) + { xmlReader->readNext(); - if(xmlReader->isCharacters() && !xmlReader->isWhitespace()) { + if (xmlReader->isCharacters() && !xmlReader->isWhitespace()) + { setTextValue(xmlReader->text().toString()); - } else if(xmlReader->isStartElement()) { + } + else if (xmlReader->isStartElement()) + { XmlObject c; c.fromXml(xmlReader); childList.append(c); - } else if(xmlReader->isEndElement()) { + } + else if (xmlReader->isEndElement()) + { return; } } } -void XmlObject::copy(const XmlObject& other) { +void XmlObject::copy(const XmlObject& other) +{ childList.clear(); attributes.clear(); setObjectName(other.getObjectName()); setTextValue(other.getTextValue()); - for(QString attr : other.attributes.keys()) { + for (QString attr : other.attributes.keys()) + { attributes[attr] = other.attributes[attr]; } - for(int i = 0; i < other.childCount(); i++) { + for (int i = 0; i < other.childCount(); i++) + { addChild(other.childAt(i)); } } +QString XmlObject::getTextValue() const { return textValue; } -QString XmlObject::getTextValue() const { - return textValue; -} +void XmlObject::setTextValue(const QString& value) { textValue = value; } -void XmlObject::setTextValue(const QString& value) { - textValue = value; -} - -QList<XmlObject*> XmlObject::deepSearchObjects(const QString& objectName) { - auto pred = [objectName](const XmlObject * obj) { - return obj->getObjectName() == objectName; - }; +QList<XmlObject*> XmlObject::deepSearchObjects(const QString& objectName) +{ + auto pred = [objectName](const XmlObject* obj) + { return obj->getObjectName() == objectName; }; return deepSearchObjects(pred); } -QList<XmlObject*> XmlObject::deepSearchObjects(std::function<bool (const XmlObject* obj)> predicate) { +QList<XmlObject*> XmlObject::deepSearchObjects( + std::function<bool(const XmlObject* obj)> predicate) +{ QList<XmlObject*> results; - if(predicate(this)) { + if (predicate(this)) + { results.append(this); } - for(int i = 0; i < childCount(); i++) { + for (int i = 0; i < childCount(); i++) + { XmlObject* child = getChild(i); results.append(child->deepSearchObjects(predicate)); } @@ -140,75 +157,83 @@ QList<XmlObject*> XmlObject::deepSearchObjects(std::function<bool (const XmlObje return results; } -void XmlObject::operator =(const XmlObject& other) { - copy(other); -} +void XmlObject::operator=(const XmlObject& other) { copy(other); } -void XmlObject::removeChild(int i) { - if( i < childCount()) +void XmlObject::removeChild(int i) +{ + if (i < childCount()) childList.removeAt(i); } -void XmlObject::swapChildAt(int i, int j) { - if(i > 0 && j > 0 && i < childCount() && j < childCount()) { +void XmlObject::swapChildAt(int i, int j) +{ + if (i > 0 && j > 0 && i < childCount() && j < childCount()) + { childList.swapItemsAt(i, j); } } -QString XmlObject::getChildObjectValue(const QString& objectName) { - for(XmlObject child : childList) { - if(child.getObjectName() == objectName) { +QString XmlObject::getChildObjectValue(const QString& objectName) +{ + for (XmlObject child : childList) + { + if (child.getObjectName() == objectName) + { return child.getTextValue(); } } return ""; } -void XmlObject::clearAttributes() { - attributes.clear(); -} +void XmlObject::clearAttributes() { attributes.clear(); } -void XmlObject::clearChilds() { - childList.clear(); -} +void XmlObject::clearChilds() { childList.clear(); } -void XmlObject::reset() { +void XmlObject::reset() +{ setObjectName(""); clearChilds(); clearAttributes(); } -bool XmlObject::isEmpty() { - return getObjectName() == "" && childList.isEmpty() && getTextValue() == "" && attributes.isEmpty(); +bool XmlObject::isEmpty() +{ + return getObjectName() == "" && childList.isEmpty() && + getTextValue() == "" && attributes.isEmpty(); } - -QString XmlObject::getAttribute(const QString& name, const QString& defaultValue) const { - if(attributes.contains(name)) { +QString XmlObject::getAttribute(const QString& name, + const QString& defaultValue) const +{ + if (attributes.contains(name)) + { return attributes[name]; } return defaultValue; } -bool XmlObject::hasAttribute(const QString& name) const { +bool XmlObject::hasAttribute(const QString& name) const +{ return attributes.contains(name); } -int XmlObject::attributeCount() const { - return attributes.count(); -} +int XmlObject::attributeCount() const { return attributes.count(); } -QMapIterator<QString, QString> XmlObject::attributesIterator() const { +QMapIterator<QString, QString> XmlObject::attributesIterator() const +{ return QMapIterator<QString, QString>(attributes); } -bool XmlObject::getIntAttribute(const QString& name, int& value) const { +bool XmlObject::getAttribute(const QString& name, int& value) const +{ QString val = getAttribute(name); bool ok; - if(val != "") { + if (val != "") + { int temp = val.toInt(&ok); - if(ok) { + if (ok) + { value = temp; return true; } @@ -216,12 +241,15 @@ bool XmlObject::getIntAttribute(const QString& name, int& value) const { return false; } -bool XmlObject::getFloatAttribute(const QString& name, float& value) const { +bool XmlObject::getAttribute(const QString& name, float& value) const +{ QString val = getAttribute(name); bool ok; - if(val != "") { + if (val != "") + { float temp = val.toFloat(&ok); - if(ok) { + if (ok) + { value = temp; return true; } @@ -229,48 +257,49 @@ bool XmlObject::getFloatAttribute(const QString& name, float& value) const { return false; } -void XmlObject::addAttribute(const QString& name, const QString& value) { +void XmlObject::addAttribute(const QString& name, const QString& value) +{ attributes[name] = value; } -void XmlObject::addAttribute(const QString& name, int value) { +void XmlObject::addAttribute(const QString& name, int value) +{ addAttribute(name, QString::number(value)); } -int XmlObject::addChild(const XmlObject& c) { +void XmlObject::addAttribute(const QString& name, float value) +{ + addAttribute(name, QString::number(value)); +} + +int XmlObject::addChild(const XmlObject& c) +{ childList.append(c); return childList.count() - 1; } -void XmlObject::addChilds(const QList<XmlObject>& childs) { +void XmlObject::addChilds(const QList<XmlObject>& childs) +{ childList.append(childs); } -QString XmlObject::getObjectName() const { - return xmlObjectName; -} +QString XmlObject::getObjectName() const { return xmlObjectName; } -void XmlObject::setObjectName(const QString& value) { - xmlObjectName = value; -} +void XmlObject::setObjectName(const QString& value) { xmlObjectName = value; } -int XmlObject::childCount() const { - return childList.count(); -} +int XmlObject::childCount() const { return childList.count(); } -XmlObject XmlObject::childAt(int index) const { - return childList.at(index); -} +XmlObject XmlObject::childAt(int index) const { return childList.at(index); } -XmlObject XmlObject::searchChild(const QString& name) const { - for(int i = 0; i < childCount(); i++) { - if(childList[i].getObjectName() == name) { - return childList[i]; - } - } - return XmlObject(); -} +int XmlObject::searchChild(const QString& name) const +{ + for (int i = 0; i < childCount(); i++) + if (childList[i].getObjectName() == name) + return i; -XmlObject* XmlObject::getChild(int index) { - return &childList[index]; + return -1; } + +XmlObject* XmlObject::getChild(int index) { return &childList[index]; } + +QMap<QString, QString> XmlObject::getAttributes() const { return attributes; } \ No newline at end of file diff --git a/Core/xmlobject.h b/Core/xmlobject.h index 9f133a17d46379b6555e88e2c203cb5a9e073462..22080dbc0475d4379c70d8523fb9177363fac9d6 100644 --- a/Core/xmlobject.h +++ b/Core/xmlobject.h @@ -1,39 +1,43 @@ #ifndef XMLOBJECT_H #define XMLOBJECT_H - #include <QMap> -#include <QXmlStreamWriter> -#include <QXmlStreamReader> #include <QMapIterator> +#include <QXmlStreamReader> +#include <QXmlStreamWriter> -class XmlObject { - public: +class XmlObject +{ +public: XmlObject(const QString& objectName = "Object"); XmlObject(const XmlObject& other); bool loadFromFile(const QString& filePath); - bool writeToFile(const QString& filePath, const QString& codec = "UTF-8") const; + bool writeToFile(const QString& filePath, + const QString& codec = "UTF-8") const; QString toXml() const; void fromXml(const QString& txt); - QString getAttribute(const QString& name, const QString& defaultValue = "") const; + QString getAttribute(const QString& name, + const QString& defaultValue = "") const; bool hasAttribute(const QString& name) const; int attributeCount() const; QMapIterator<QString, QString> attributesIterator() const; /* - * Get the value of "value" if the attribute with name "name" exist and is an integer + * Get the value of "value" if the attribute with name "name" exist and is + * an integer */ - bool getIntAttribute(const QString& name, int& value) const; - bool getFloatAttribute(const QString& name, float& value) const; + bool getAttribute(const QString& name, int& value) const; + bool getAttribute(const QString& name, float& value) const; /* * addAttribute create a new attribute with name "name" and value "value" * If the attribute already exist, it change its value */ void addAttribute(const QString& name, const QString& value); void addAttribute(const QString& name, int value); + void addAttribute(const QString& name, float value); int addChild(const XmlObject& c); void addChilds(const QList<XmlObject>& childs); @@ -42,7 +46,7 @@ class XmlObject { int childCount() const; XmlObject childAt(int index) const; - XmlObject searchChild(const QString& name) const; + int searchChild(const QString& name) const; /* * getChild Returns the child at index position as a modifiable reference. * index must be a valid index position in the list @@ -59,10 +63,11 @@ class XmlObject { /* * deepSearchObjects return all the child objects that satisfy the predicate */ - QList<XmlObject*> deepSearchObjects(std::function<bool(const XmlObject* obj)> predicate); + QList<XmlObject*> deepSearchObjects( + std::function<bool(const XmlObject* obj)> predicate); QList<XmlObject*> deepSearchObjects(const QString& objectName); - void operator = (const XmlObject& other ); + void operator=(const XmlObject& other); void removeChild(int i); /* @@ -78,17 +83,19 @@ class XmlObject { void reset(); bool isEmpty(); - protected: + + QMap<QString, QString> getAttributes() const; + +protected: void toXml(QXmlStreamWriter* xmlWriter) const; void fromXml(QXmlStreamReader* xmlReader); void copy(const XmlObject& other); - private: +private: QMap<QString, QString> attributes; QList<XmlObject> childList; - QString textValue = ""; + QString textValue = ""; QString xmlObjectName = ""; - }; -#endif // XMLOBJECT_H +#endif // XMLOBJECT_H diff --git a/Modules/CommandPad/MessageFormElement.cpp b/Modules/CommandPad/MessageFormElement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0feed91cf32e1ae82f6f13785ef53af601ac59b --- /dev/null +++ b/Modules/CommandPad/MessageFormElement.cpp @@ -0,0 +1,311 @@ +#include "MessageFormElement.h" + +#include <Modules/skywardhubstrings.h> + +MessageFormElement::MessageFormElement() {} + +MessageFormElement::~MessageFormElement() +{ + for (auto key : comboBoxMap.keys()) + { + delete comboBoxMap[key].first; + delete comboBoxMap[key].second; + } + + for (auto key : floatMap.keys()) + { + delete std::get<0>(floatMap[key]); + delete std::get<1>(floatMap[key]); + } + + for (auto key : integerMap.keys()) + { + delete std::get<0>(integerMap[key]); + delete std::get<1>(integerMap[key]); + } +} + +bool MessageFormElement::addComboBox(QString id, QString label, + const QMap<QString, int>& options) +{ + if (!comboBoxMap.contains(id) && !floatMap.contains(id) && + !integerMap.contains(id)) + { + auto* comboBox = new QComboBox; + comboBox->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + + for (auto key : options.keys()) + comboBox->addItem(key, options[key]); + + comboBoxMap[id] = {new QLabel(label), comboBox}; + return true; + } + else + { + return false; + } +} + +bool MessageFormElement::addFloat(QString id, QString label, float min, + float max, int decimals) +{ + if (!comboBoxMap.contains(id) && !floatMap.contains(id) && + !integerMap.contains(id)) + { + auto* lineEdit = new QLineEdit; + lineEdit->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + lineEdit->setValidator(new QDoubleValidator(min, max, decimals)); + floatMap[id] = {new QLabel(label), lineEdit, min, max, decimals}; + return true; + } + else + { + return false; + } +} + +bool MessageFormElement::addInteger(QString id, QString label, int min, int max) +{ + if (!comboBoxMap.contains(id) && !floatMap.contains(id) && + !integerMap.contains(id)) + { + auto* lineEdit = new QLineEdit; + lineEdit->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + lineEdit->setValidator(new QIntValidator(min, max)); + integerMap[id] = {new QLabel(label), lineEdit, min, max}; + return true; + } + else + { + return false; + } +} + +XmlObject MessageFormElement::toXmlObject() +{ + XmlObject comboBoxList("combo_box_list"); + for (auto key : comboBoxMap.keys()) + { + auto comboBox = comboBoxMap[key]; + XmlObject comboBoxXml("combo_box"); + comboBoxXml.addAttribute("id", key); + comboBoxXml.addAttribute("label", comboBox.first->text()); + comboBoxXml.addAttribute("text", comboBox.second->currentText()); + comboBoxList.addChild(comboBoxXml); + } + + XmlObject floatList("float_list"); + for (auto key : floatMap.keys()) + { + auto floatField = floatMap[key]; + XmlObject floatFieldXml("float_field"); + floatFieldXml.addAttribute("id", key); + floatFieldXml.addAttribute("label", std::get<0>(floatField)->text()); + floatFieldXml.addAttribute("text", std::get<1>(floatField)->text()); + floatFieldXml.addAttribute("min", std::get<2>(floatField)); + floatFieldXml.addAttribute("max", std::get<3>(floatField)); + floatFieldXml.addAttribute("decimals", std::get<4>(floatField)); + floatList.addChild(floatFieldXml); + } + + XmlObject integerList("integer_list"); + for (auto key : floatMap.keys()) + { + auto integerField = floatMap[key]; + XmlObject integerFieldXml("integer_field"); + integerFieldXml.addAttribute("id", key); + integerFieldXml.addAttribute("label", + std::get<0>(integerField)->text()); + integerFieldXml.addAttribute("text", std::get<1>(integerField)->text()); + integerFieldXml.addAttribute("min", std::get<2>(integerField)); + integerFieldXml.addAttribute("max", std::get<3>(integerField)); + integerList.addChild(integerFieldXml); + } + + XmlObject configuration("configuration"); + configuration.addChild(comboBoxList); + configuration.addChild(floatList); + configuration.addChild(integerList); + + return configuration; +} + +void MessageFormElement::fromXmlObject(const XmlObject& obj) +{ + int comboBoxListIndex = obj.searchChild("combo_box_list"); + if (comboBoxListIndex != -1) + { + auto comboBoxList = obj.childAt(comboBoxListIndex); + for (int i = 0; i < comboBoxList.childCount(); i++) + { + auto comboBoxXml = comboBoxList.childAt(i); + auto key = comboBoxXml.getAttribute("id"); + if (comboBoxMap.contains(key)) + { + auto comboBox = comboBoxMap[key]; + comboBox.first->setText(comboBoxXml.getAttribute("label")); + comboBox.second->setCurrentText( + comboBoxXml.getAttribute("text")); + } + } + } + + int floatListIndex = obj.searchChild("float_list"); + if (floatListIndex != -1) + { + auto floatList = obj.childAt(floatListIndex); + for (int i = 0; i < floatList.childCount(); i++) + { + auto floatFieldXml = floatList.childAt(i); + auto key = floatFieldXml.getAttribute("id"); + if (floatMap.contains(key)) + { + auto floatField = floatMap[key]; + std::get<0>(floatField) + ->setText(floatFieldXml.getAttribute("label")); + std::get<1>(floatField) + ->setText(floatFieldXml.getAttribute("text")); + floatFieldXml.getAttribute("min", std::get<2>(floatField)); + floatFieldXml.getAttribute("max", std::get<3>(floatField)); + floatFieldXml.getAttribute("decimals", std::get<4>(floatField)); + std::get<1>(floatField) + ->setValidator(new QDoubleValidator( + std::get<2>(floatField), std::get<3>(floatField), + std::get<4>(floatField))); + } + } + } + + int integerListIndex = obj.searchChild("integer_list"); + if (integerListIndex != -1) + { + auto floatList = obj.childAt(integerListIndex); + for (int i = 0; i < floatList.childCount(); i++) + { + auto integerFieldXml = floatList.childAt(i); + auto key = integerFieldXml.getAttribute("id"); + if (integerMap.contains(key)) + { + auto integerField = integerMap[key]; + std::get<0>(integerField) + ->setText(integerFieldXml.getAttribute("label")); + std::get<1>(integerField) + ->setText(integerFieldXml.getAttribute("text")); + integerFieldXml.getAttribute("min", std::get<2>(integerField)); + integerFieldXml.getAttribute("max", std::get<3>(integerField)); + std::get<1>(integerField) + ->setValidator(new QIntValidator( + std::get<2>(integerField), std::get<3>(integerField))); + } + } + } +} + +void MessageFormElement::applyToGridLayout(QGridLayout* layout) +{ + for (auto key : comboBoxMap.keys()) + { + auto label = comboBoxMap[key].first; + auto comboBox = comboBoxMap[key].second; + + int rows = layout->rowCount(); + layout->addWidget(label, rows, 0, Qt::AlignRight); + layout->addWidget(comboBox, rows, 1); + + label->show(); + comboBox->show(); + } + + for (auto key : floatMap.keys()) + { + auto label = std::get<0>(floatMap[key]); + auto floatField = std::get<1>(floatMap[key]); + + int rows = layout->rowCount(); + layout->addWidget(label, rows, 0, Qt::AlignRight); + layout->addWidget(floatField, rows, 1); + + label->show(); + floatField->show(); + } + + for (auto key : integerMap.keys()) + { + auto label = std::get<0>(integerMap[key]); + auto integerField = std::get<1>(integerMap[key]); + + int rows = layout->rowCount(); + layout->addWidget(label, rows, 0, Qt::AlignRight); + layout->addWidget(integerField, rows, 1); + + label->show(); + integerField->show(); + } +} + +void MessageFormElement::removeFromGridLayout(QGridLayout* layout) +{ + for (auto key : comboBoxMap.keys()) + { + auto label = comboBoxMap[key].first; + auto comboBox = comboBoxMap[key].second; + + layout->removeWidget(label); + layout->removeWidget(comboBox); + + label->hide(); + comboBox->hide(); + } + + for (auto key : floatMap.keys()) + { + auto label = std::get<0>(floatMap[key]); + auto floatField = std::get<1>(floatMap[key]); + + layout->removeWidget(label); + layout->removeWidget(floatField); + + label->hide(); + floatField->hide(); + } + + for (auto key : integerMap.keys()) + { + auto label = std::get<0>(integerMap[key]); + auto integerField = std::get<1>(integerMap[key]); + + layout->removeWidget(label); + layout->removeWidget(integerField); + + label->hide(); + integerField->hide(); + } +} + +ModuleMessage MessageFormElement::prepareMessage(const QString& messageId) +{ + ModuleMessage message(SkywardHubStrings::commandsTopic + "/" + messageId); + + for (auto key : comboBoxMap.keys()) + { + auto comboBox = comboBoxMap[key].second; + message.setField(key, (uint64_t)comboBox->currentData().toInt()); + } + + for (auto key : floatMap.keys()) + { + auto floatField = std::get<1>(floatMap[key]); + message.setField(key, floatField->text()); + } + + for (auto key : integerMap.keys()) + { + auto integerField = std::get<1>(integerMap[key]); + message.setField(key, integerField->text()); + } + + return message; +} \ No newline at end of file diff --git a/Modules/CommandPad/MessageFormElement.h b/Modules/CommandPad/MessageFormElement.h new file mode 100644 index 0000000000000000000000000000000000000000..81946d49e7000e38e15db99bd564601a6fbd796a --- /dev/null +++ b/Modules/CommandPad/MessageFormElement.h @@ -0,0 +1,61 @@ +#pragma once + +#include <Core/Message/modulemessage.h> +#include <Core/xmlobject.h> + +#include <QComboBox> +#include <QGridLayout> +#include <QLabel> +#include <QLineEdit> +#include <QMap> +#include <QString> + +class MessageFormElement +{ +public: + MessageFormElement(); + + ~MessageFormElement(); + + /** + * @brief Adds a new combo box field to the form. + * + * @return false if there is already a field with the given id. + */ + bool addComboBox(QString id, QString label, + const QMap<QString, int>& options); + + /** + * @brief Adds a new float field to the form. + * + * @return false if there is already a field with the given id. + */ + bool addFloat(QString id, QString label, + float min = std::numeric_limits<float>::min(), + float max = std::numeric_limits<float>::max(), + int decimals = 2); + + /** + * @brief Adds a new integer field to the form. + * + * @return false if there is already a field with the given id. + */ + bool addInteger(QString id, QString label, + int min = std::numeric_limits<int>::min(), + int max = std::numeric_limits<int>::max()); + + XmlObject toXmlObject(); + + void fromXmlObject(const XmlObject& obj); + + void applyToGridLayout(QGridLayout* layout); + + void removeFromGridLayout(QGridLayout* layout); + + ModuleMessage prepareMessage(const QString& messageId); + +private: + QMap<QString, QPair<QLabel*, QComboBox*>> comboBoxMap; + QMap<QString, std::tuple<QLabel*, QLineEdit*, float, float, int>> floatMap; + QMap<QString, std::tuple<QLabel*, QLineEdit*, int, int>> integerMap; +}; diff --git a/Modules/CommandPad/commandpad.cpp b/Modules/CommandPad/commandpad.cpp index 2967182168f612c798885e882ea226846d73a83b..411d82bf656926ab6b537a71f289c051d8ef1830 100644 --- a/Modules/CommandPad/commandpad.cpp +++ b/Modules/CommandPad/commandpad.cpp @@ -2,253 +2,252 @@ #include <QVBoxLayout> -const QMap<QString, uint8_t> CommandPad::systemTMList{ - {"MAV_SYS_ID", 1}, {"MAV_FSM_ID", 2}, - {"MAV_PIN_OBS_ID", 3}, {"MAV_LOGGER_ID", 4}, - {"MAV_MAVLINK_STATS", 5}, {"MAV_TASK_STATS_ID", 6}, - {"MAV_ADA_ID", 8}, {"MAV_NAS_ID", 9}, - {"MAV_CAN_ID", 10}, {"MAV_FLIGHT_ID", 11}, - {"MAV_FLIGHT_STATS_ID", 12}, {"MAV_SENSORS_STATE_ID", 13}}; - -const QMap<QString, uint8_t> CommandPad::sensorsTMList = { - {"MAV_GPS_ID", 1}, - {"MAV_BMX160_ID", 2}, - {"MAV_VN100_ID", 3}, - {"MAV_MPU9250_ID", 4}, - {"MAV_ADS_ID", 5}, - {"MAV_MS5803_ID", 6}, - {"MAV_BME280_ID", 7}, - {"MAV_CURRENT_SENSE_ID", 8}, - {"MAV_LIS3MDL_ID", 9}, - {"MAV_DPL_PRESS_ID", 10}, - {"MAV_STATIC_PRESS_ID", 11}, - {"MAV_PITOT_PRESS_ID", 12}, - {"MAV_BATTERY_VOLTAGE_ID", 13}, - {"MAV_STRAIN_GAUGE_ID", 14}, +#include "Modules/Mavlink/mavlinkversionheader.h" + +const QStringList CommandPad::messagesList{ + "PING_TC", + "COMMAND_TC", + "SYSTEM_TM_REQUEST_TC", + "SENSOR_TM_REQUEST_TC", + "SERVO_TM_REQUEST_TC", + "SET_SERVO_ANGLE_TC", + "WIGGLE_SERVO_TC", + "RESET_SERVO_TC", + "SET_REFERENCE_ALTITUDE_TC", + "SET_REFERENCE_TEMPERATURE_TC", + "SET_ORIENTATION_TC", + "SET_COORDINATES_TC", + "RAW_EVENT_TC", + "SET_DEPLOYMENT_ALTITUDE_TC", + "SET_TARGET_COORDINATES_TC", + "SET_ALGORITHM_TC", }; -const QMap<QString, uint8_t> CommandPad::mavCommandList = { - {"MAV_CMD_ARM", 1}, - {"MAV_CMD_DISARM", 2}, - {"MAV_CMD_CALIBRATE", 3}, - {"MAV_CMD_FORCE_INIT", 4}, - {"MAV_CMD_FORCE_LAUNCH", 5}, - {"MAV_CMD_FORCE_LANDING", 6}, - {"MAV_CMD_FORCE_APOGEE", 7}, - {"MAV_CMD_FORCE_EXPULSION", 8}, - {"MAV_CMD_FORCE_MAIN", 9}, - {"MAV_CMD_START_LOGGING", 10}, - {"MAV_CMD_CLOSE_LOG", 11}, - {"MAV_CMD_FORCE_REBOOT", 12}, - {"MAV_CMD_ENTER_TEST_MODE", 13}, - {"MAV_CMD_EXIT_TEST_MODE", 14}, - {"MAV_CMD_START_RECORDING", 15}, - {"MAV_CMD_STOP_RECORDING", 16}, +const QMap<QString, int> CommandPad::systemTmList{ + {"MAV_SYS_ID", MAV_SYS_ID}, + {"MAV_FSM_ID", MAV_FSM_ID}, + {"MAV_PIN_OBS_ID", MAV_PIN_OBS_ID}, + {"MAV_LOGGER_ID", MAV_LOGGER_ID}, + {"MAV_MAVLINK_STATS", MAV_MAVLINK_STATS}, + {"MAV_TASK_STATS_ID", MAV_TASK_STATS_ID}, + {"MAV_ADA_ID", MAV_ADA_ID}, + {"MAV_NAS_ID", MAV_NAS_ID}, + {"MAV_CAN_ID", MAV_CAN_ID}, + {"MAV_FLIGHT_ID", MAV_FLIGHT_ID}, + {"MAV_STATS_ID", MAV_STATS_ID}, + {"MAV_SENSORS_STATE_ID", MAV_SENSORS_STATE_ID}, }; -const QMap<QString, uint8_t> CommandPad::servosList = { - {"AIRBRAKES_SERVO", 1}, - {"EXPULSION_SERVO", 2}, - {"PARAFOIL_SERVO1", 3}, - {"PARAFOIL_SERVO2", 4}, +const QMap<QString, int> CommandPad::sensorsList{ + {"MAV_GPS_ID", MAV_GPS_ID}, + {"MAV_BMX160_ID", MAV_BMX160_ID}, + {"MAV_VN100_ID", MAV_VN100_ID}, + {"MAV_MPU9250_ID", MAV_MPU9250_ID}, + {"MAV_ADS_ID", MAV_ADS_ID}, + {"MAV_MS5803_ID", MAV_MS5803_ID}, + {"MAV_BME280_ID", MAV_BME280_ID}, + {"MAV_CURRENT_SENSE_ID", MAV_CURRENT_SENSE_ID}, + {"MAV_LIS3MDL_ID", MAV_LIS3MDL_ID}, + {"MAV_DPL_PRESS_ID", MAV_DPL_PRESS_ID}, + {"MAV_STATIC_PRESS_ID", MAV_STATIC_PRESS_ID}, + {"MAV_PITOT_PRESS_ID", MAV_PITOT_PRESS_ID}, + {"MAV_BATTERY_VOLTAGE_ID", MAV_BATTERY_VOLTAGE_ID}, + {"MAV_STRAIN_GAUGE_ID", MAV_STRAIN_GAUGE_ID}, }; -CommandPad::CommandPad(QWidget *parent) : DefaultModule(parent) { +const QMap<QString, int> CommandPad::commandsList{ + {"MAV_CMD_ARM", MAV_CMD_ARM}, + {"MAV_CMD_DISARM", MAV_CMD_DISARM}, + {"MAV_CMD_CALIBRATE", MAV_CMD_CALIBRATE}, + {"MAV_CMD_FORCE_INIT", MAV_CMD_FORCE_INIT}, + {"MAV_CMD_FORCE_LAUNCH", MAV_CMD_FORCE_LAUNCH}, + {"MAV_CMD_FORCE_LANDING", MAV_CMD_FORCE_LANDING}, + {"MAV_CMD_FORCE_APOGEE", MAV_CMD_FORCE_APOGEE}, + {"MAV_CMD_FORCE_EXPULSION", MAV_CMD_FORCE_EXPULSION}, + {"MAV_CMD_FORCE_MAIN", MAV_CMD_FORCE_MAIN}, + {"MAV_CMD_START_LOGGING", MAV_CMD_START_LOGGING}, + {"MAV_CMD_CLOSE_LOG", MAV_CMD_CLOSE_LOG}, + {"MAV_CMD_FORCE_REBOOT", MAV_CMD_FORCE_REBOOT}, + {"MAV_CMD_ENTER_TEST_MODE", MAV_CMD_ENTER_TEST_MODE}, + {"MAV_CMD_EXIT_TEST_MODE", MAV_CMD_EXIT_TEST_MODE}, + {"MAV_CMD_START_RECORDING", MAV_CMD_START_RECORDING}, + {"MAV_CMD_STOP_RECORDING", MAV_CMD_STOP_RECORDING}, +}; + +const QMap<QString, int> CommandPad::servosList{ + {"AIRBRAKES_SERVO", AIRBRAKES_SERVO}, + {"EXPULSION_SERVO", EXPULSION_SERVO}, + {"PARAFOIL_SERVO1", PARAFOIL_SERVO1}, + {"PARAFOIL_SERVO2", PARAFOIL_SERVO2}, +}; + +CommandPad::CommandPad(QWidget *parent) : DefaultModule(parent) +{ setupUi(); defaultContextMenuSetup(); } -CommandPad::~CommandPad() {} +CommandPad::~CommandPad() +{ + delete messagesListComboBox; + for (auto key : formElements.keys()) + delete formElements[key]; + delete formGridLayout; +} QWidget *CommandPad::toWidget() { return this; } -XmlObject CommandPad::toXmlObject() { - return XmlObject(getName(ModuleId::COMMANDPAD)); -} +XmlObject CommandPad::toXmlObject() +{ + XmlObject obj = XmlObject(getName(ModuleId::COMMANDPAD)); -void CommandPad::fromXmlObject(const XmlObject &xmlObject) { - Q_UNUSED(xmlObject); + auto key = messagesListComboBox->currentText(); + if (formElements.contains(key)) + { + obj.addAttribute("message_id", key); + obj.addChild(formElements[key]->toXmlObject()); + } + + return obj; } -#define _CMD(id, strName) \ - QWidget *id = new QWidget; \ - QFormLayout *id##_form = new QFormLayout; \ - id->setLayout(id##_form); \ - stacked->addWidget(id); \ - commandComboBox->addItem(strName); - -#define _CMD_FLOAT_PROP(id, idProperty) \ - QLineEdit *id##_##idProperty = new QLineEdit; \ - id##_##idProperty->setValidator( \ - new QDoubleValidator(-10000.0, 10000.0, 3, this)); \ - id##_##idProperty->setSizePolicy( \ - QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); \ - id##_form->addRow(tr(#idProperty ": "), id##_##idProperty); - -#define _CMD_UINT8_PROP(id, idProperty) \ - QLineEdit *id##_##idProperty = new QLineEdit; \ - id##_##idProperty->setValidator(new QIntValidator(0, 255, this)); \ - id##_##idProperty->setSizePolicy( \ - QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); \ - id##_form->addRow(tr(#idProperty ": "), id##_##idProperty); - -#define _CMD_COMBO_PROP(id, idProperty, map) \ - QComboBox *id##_##idProperty = new QComboBox; \ - id##_##idProperty->setSizePolicy( \ - QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); \ - id##_##idProperty->insertItems(0, map.keys()); \ - id##_form->addRow(tr(#idProperty ": "), id##_##idProperty); - -#define _CMD_END - -#define _SEND(id, strName) \ - if (commandComboBox->currentText() == strName) { \ - QTime time = QTime::currentTime(); \ - ModuleMessage message(SkywardHubStrings::commandsTopic + "/" + \ - strName); \ - message.setField("timestamp", (uint64_t)time.msecsSinceStartOfDay()); - -#define _SEND_FLOAT_PROP(id, idProperty) \ - message.setField(#idProperty, id##_##idProperty->text().toDouble()); - -#define _SEND_UINT8_PROP(id, idProperty) \ - message.setField(#idProperty, (uint64_t)id##_##idProperty->text().toInt()); - -#define _SEND_COMBO_PROP(id, idProperty, map) \ - message.setField(#idProperty, \ - (uint64_t)map[id##_##idProperty->currentText()]); - -#define _SEND_END \ - getCore()->getModuleMessagesBroker()->publish(message); \ +void CommandPad::fromXmlObject(const XmlObject &obj) +{ + int configurationIndex = obj.searchChild("configuration"); + if (obj.hasAttribute("message_id") && configurationIndex != -1) + { + auto key = obj.getAttribute("message_id"); + + if (formElements.contains(key)) + { + auto configuration = obj.childAt(configurationIndex); + formElements[key]->fromXmlObject(configuration); + messagesListComboBox->setCurrentText(key); + } } +} + +void CommandPad::removeWidgetsFromForm() +{ + QLayoutItem *child; + while ((child = formGridLayout->takeAt(0)) != nullptr) + formGridLayout->removeWidget(child->widget()); +} -void CommandPad::setupUi() { - QStackedWidget *stacked = new QStackedWidget; +void CommandPad::setupUi() +{ + QVBoxLayout *outerLayout = new QVBoxLayout; + outerLayout->addStretch(); - QComboBox *commandComboBox = new QComboBox; - commandComboBox->setSizePolicy( + messagesListComboBox = new QComboBox; + messagesListComboBox->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); - connect(commandComboBox, - QOverload<int>::of(&QComboBox::currentIndexChanged), this, - [=](int idx) { stacked->setCurrentIndex(idx); }); - - QFormLayout *form = new QFormLayout; - form->addRow(tr("Select command: "), commandComboBox); - - _CMD(ping, "PING_TC") - _CMD_END - _CMD(command, "COMMAND_TC") - _CMD_COMBO_PROP(command, command_id, mavCommandList) - _CMD_END - _CMD(systemTelemetry, "SYSTEM_TM_REQUEST_TC") - _CMD_COMBO_PROP(systemTelemetry, tm_id, systemTMList) - _CMD_END - _CMD(sensorTelemetry, "SENSOR_TM_REQUEST_TC") - _CMD_COMBO_PROP(sensorTelemetry, sensor_id, sensorsTMList) - _CMD_END - _CMD(servoTelemetry, "SERVO_TM_REQUEST_TC") - _CMD_COMBO_PROP(servoTelemetry, servo_id, servosList) - _CMD_END - _CMD(setServoAngle, "SET_SERVO_ANGLE_TC") - _CMD_COMBO_PROP(setServoAngle, servo_id, servosList) - _CMD_FLOAT_PROP(setServoAngle, angle) - _CMD_END - _CMD(wiggleServo, "WIGGLE_SERVO_TC") - _CMD_COMBO_PROP(wiggleServo, servo_id, servosList) - _CMD_END - _CMD(resetServo, "RESET_SERVO_TC") - _CMD_COMBO_PROP(resetServo, servo_id, servosList) - _CMD_END - _CMD(setReferenceAltitude, "SET_REFERENCE_ALTITUDE_TC") - _CMD_FLOAT_PROP(setReferenceAltitude, ref_altitude) - _CMD_END - _CMD(setReferenceTemperature, "SET_REFERENCE_TEMPERATURE_TC") - _CMD_FLOAT_PROP(setReferenceTemperature, ref_temp) - _CMD_END - _CMD(setDeploymentAltitude, "SET_DEPLOYMENT_ALTITUDE_TC") - _CMD_FLOAT_PROP(setDeploymentAltitude, dpl_altitude) - _CMD_END - _CMD(setOrientation, "SET_ORIENTATION_TC") - _CMD_FLOAT_PROP(setOrientation, yaw) - _CMD_FLOAT_PROP(setOrientation, pitch) - _CMD_FLOAT_PROP(setOrientation, roll) - _CMD_END - _CMD(setCoordinates, "SET_COORDINATES_TC") - _CMD_FLOAT_PROP(setCoordinates, latitude) - _CMD_FLOAT_PROP(setCoordinates, longitude) - _CMD_END - _CMD(rawEvent, "RAW_EVENT_TC") - _CMD_UINT8_PROP(rawEvent, topic_id) - _CMD_UINT8_PROP(rawEvent, event_id) - _CMD_END - _CMD(targetCoordinates, "SET_TARGET_COORDINATES_TC") - _CMD_FLOAT_PROP(targetCoordinates, latitude) - _CMD_FLOAT_PROP(targetCoordinates, longitude) - _CMD_END - _CMD(algorithm, "SET_ALGORITHM_TC") - _CMD_UINT8_PROP(algorithm, algorithm_number) - _CMD_END - - QPushButton *send = new QPushButton(tr("Send")); - connect(send, &QPushButton::clicked, [=]() { - _SEND(ping, "PING_TC") - _SEND_END - _SEND(command, "COMMAND_TC") - _SEND_COMBO_PROP(command, command_id, mavCommandList) - _SEND_END - _SEND(systemTelemetry, "SYSTEM_TM_REQUEST_TC") - _SEND_COMBO_PROP(systemTelemetry, tm_id, systemTMList) - _SEND_END - _SEND(sensorTelemetry, "SENSOR_TM_REQUEST_TC") - _SEND_COMBO_PROP(sensorTelemetry, sensor_id, sensorsTMList) - _SEND_END - _SEND(servoTelemetry, "SERVO_TM_REQUEST_TC") - _SEND_COMBO_PROP(servoTelemetry, servo_id, servosList) - _SEND_END - _SEND(setServoAngle, "SET_SERVO_ANGLE_TC") - _SEND_COMBO_PROP(setServoAngle, servo_id, servosList) - _SEND_FLOAT_PROP(setServoAngle, angle) - _SEND_END - _SEND(wiggleServo, "WIGGLE_SERVO_TC") - _SEND_COMBO_PROP(wiggleServo, servo_id, servosList) - _SEND_END - _SEND(resetServo, "RESET_SERVO_TC") - _SEND_COMBO_PROP(resetServo, servo_id, servosList) - _SEND_END - _SEND(setReferenceAltitude, "SET_REFERENCE_ALTITUDE_TC") - _SEND_FLOAT_PROP(setReferenceAltitude, ref_altitude) - _SEND_END - _SEND(setReferenceTemperature, "SET_REFERENCE_TEMPERATURE_TC") - _SEND_FLOAT_PROP(setReferenceTemperature, ref_temp) - _SEND_END - _SEND(setDeploymentAltitude, "SET_DEPLOYMENT_ALTITUDE_TC") - _SEND_FLOAT_PROP(setDeploymentAltitude, dpl_altitude) - _SEND_END - _SEND(setOrientation, "SET_ORIENTATION_TC") - _SEND_FLOAT_PROP(setOrientation, yaw) - _SEND_FLOAT_PROP(setOrientation, pitch) - _SEND_FLOAT_PROP(setOrientation, roll) - _SEND_END - _SEND(setCoordinates, "SET_COORDINATES_TC") - _SEND_FLOAT_PROP(setCoordinates, latitude) - _SEND_FLOAT_PROP(setCoordinates, longitude) - _SEND_END - _SEND(rawEvent, "RAW_EVENT_TC") - _SEND_UINT8_PROP(rawEvent, topic_id) - _SEND_UINT8_PROP(rawEvent, event_id) - _SEND_END - _SEND(targetCoordinates, "SET_TARGET_COORDINATES_TC") - _SEND_FLOAT_PROP(targetCoordinates, latitude) - _SEND_FLOAT_PROP(targetCoordinates, longitude) - _SEND_END - _SEND(algorithm, "SET_ALGORITHM_TC") - _SEND_UINT8_PROP(algorithm, algorithm_number) - _SEND_END - }); - - QVBoxLayout *layout = new QVBoxLayout; - layout->addLayout(form); - layout->addWidget(stacked); - layout->addWidget(send); - setLayout(layout); + messagesListComboBox->addItems(messagesList); + outerLayout->addWidget(messagesListComboBox); + + formGridLayout = new QGridLayout; + outerLayout->addLayout(formGridLayout); + + QPushButton *sendButton = new QPushButton("Send"); + outerLayout->addWidget(sendButton); + + setLayout(outerLayout); + + MessageFormElement *element; + + element = new MessageFormElement(); + formElements["PING_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("command_id", "Command:", commandsList); + formElements["COMMAND_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("tm_id", "Telemetry:", systemTmList); + formElements["SYSTEM_TM_REQUEST_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("sensor_id", "Sensor:", sensorsList); + formElements["SENSOR_TM_REQUEST_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("servo_id", "Servo:", servosList); + formElements["SERVO_TM_REQUEST_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("servo_id", "Servo:", servosList); + element->addFloat("angle", "Angle:", 0, 180, 2); + formElements["SET_SERVO_ANGLE_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("servo_id", "Servo:", servosList); + formElements["WIGGLE_SERVO_TC"] = element; + + element = new MessageFormElement(); + element->addComboBox("servo_id", "Servo:", servosList); + formElements["RESET_SERVO_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("ref_altitude", "Altitude:", 0, 9999, 2); + formElements["SET_REFERENCE_ALTITUDE_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("ref_temp", "Temperature:", 0, 999, 2); + formElements["SET_REFERENCE_TEMPERATURE_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("yaw", "Yaw:", -180, 180, 2); + element->addFloat("pitch", "Pitch:", -180, 180, 2); + element->addFloat("roll", "Roll:", -180, 180, 2); + formElements["SET_ORIENTATION_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("latitude", "Latitude:", -90, 90, 6); + element->addFloat("longitude", "Longitude:", -90, 90, 6); + formElements["SET_COORDINATES_TC"] = element; + + element = new MessageFormElement(); + element->addInteger("topic_id", "Topic:", 0, 999); + element->addInteger("event_id", "Event:", 0, 999); + formElements["RAW_EVENT_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("ref_altitude", "Altitude:", 0, 9999, 2); + formElements["SET_DEPLOYMENT_ALTITUDE_TC"] = element; + + element = new MessageFormElement(); + element->addFloat("latitude", "Latitude:", -90, 90, 6); + element->addFloat("longitude", "Longitude:", -90, 90, 6); + formElements["SET_TARGET_COORDINATES_TC"] = element; + + element = new MessageFormElement(); + element->addInteger("algorithm_number", "Algorithm:", 0, 999); + formElements["SET_ALGORITHM_TC"] = element; + + // Set default value + currentMessage = "PING_TC"; + messagesListComboBox->setCurrentText(currentMessage); + + connect(messagesListComboBox, &QComboBox::currentTextChanged, this, + [=](QString key) + { + if (formElements.contains(key)) + { + formElements[currentMessage]->removeFromGridLayout( + formGridLayout); + formElements[key]->applyToGridLayout(formGridLayout); + currentMessage = key; + } + }); + + connect(sendButton, &QPushButton::clicked, + [=]() + { + auto key = messagesListComboBox->currentText(); + if (formElements.contains(key)) + { + auto message = formElements[key]->prepareMessage(key); + getCore()->getModuleMessagesBroker()->publish(message); + } + }); } diff --git a/Modules/CommandPad/commandpad.h b/Modules/CommandPad/commandpad.h index 44bb73ef8f88130789c817bd18bca72e7a1ade4c..32427b2562aab947ec5cb3a389a1afdca87e98a7 100644 --- a/Modules/CommandPad/commandpad.h +++ b/Modules/CommandPad/commandpad.h @@ -1,16 +1,22 @@ #ifndef COMMANDPAD_H #define COMMANDPAD_H +#include <tuple> + +#include "MessageFormElement.h" #include "Modules/DefaultModule/defaultmodule.h" -class CommandPad : public DefaultModule { +class CommandPad : public DefaultModule +{ Q_OBJECT - public: - static const QMap<QString, uint8_t> systemTMList; - static const QMap<QString, uint8_t> sensorsTMList; - static const QMap<QString, uint8_t> mavCommandList; - static const QMap<QString, uint8_t> servosList; +public: + static const QStringList messagesList; + + static const QMap<QString, int> systemTmList; + static const QMap<QString, int> sensorsList; + static const QMap<QString, int> commandsList; + static const QMap<QString, int> servosList; explicit CommandPad(QWidget* parent = nullptr); ~CommandPad(); @@ -20,10 +26,14 @@ class CommandPad : public DefaultModule { XmlObject toXmlObject() override; void fromXmlObject(const XmlObject& xmlObject) override; - private: +private: + void removeWidgetsFromForm(); void setupUi(); - QComboBox* commandComboBox; + QString currentMessage; + QComboBox* messagesListComboBox; + QMap<QString, MessageFormElement*> formElements; + QGridLayout* formGridLayout; }; -#endif // COMMANDPAD_H +#endif // COMMANDPAD_H diff --git a/Modules/Splitter/splittermodule.cpp b/Modules/Splitter/splittermodule.cpp index 7818a89c17cc264dc308d45754dad682efd4af0e..0b1d7e300c65d0755fa8e200ca9d38f64dac6df6 100644 --- a/Modules/Splitter/splittermodule.cpp +++ b/Modules/Splitter/splittermodule.cpp @@ -113,7 +113,7 @@ void SplitterModule::fromXmlObject(const XmlObject& xmlObject) void SplitterModule::initialize(const XmlObject& params) { int orientation; - if (params.getIntAttribute("Orientation", orientation)) + if (params.getAttribute("Orientation", orientation)) { if (orientation == Qt::Vertical) { diff --git a/Modules/ValuesConverterViewer/valueelement.cpp b/Modules/ValuesConverterViewer/valueelement.cpp index 91a42b4b08abd1108c75c423d8bd2513c769a2f8..31d3f425927e4623da877eeebdc5d05db5d59eb1 100644 --- a/Modules/ValuesConverterViewer/valueelement.cpp +++ b/Modules/ValuesConverterViewer/valueelement.cpp @@ -1,22 +1,19 @@ #include "valueelement.h" -#include <QRadioButton> - #include <QDebug> +#include <QRadioButton> -ValueElement::ValueElement() { +ValueElement::ValueElement() {} -} +ValueElement::~ValueElement() {} -ValueElement::~ValueElement() { +ValueElement::ValueElement(const ValueElement& other) { copy(other); } -} - -ValueElement::ValueElement(const ValueElement& other) { - copy(other); -} - -ValueElement::ValueElement(const QString& name, const QString& topic, const QString& receivedValue, const QString& displayedValue, const QString& color, const QString& outputTopic) { +ValueElement::ValueElement(const QString& name, const QString& topic, + const QString& receivedValue, + const QString& displayedValue, const QString& color, + const QString& outputTopic) +{ setName(name); setTopic(topic); setReceivedValue(receivedValue); @@ -25,56 +22,46 @@ ValueElement::ValueElement(const QString& name, const QString& topic, const QStr setOutputTopic(outputTopic); } -ValueElement ValueElement::operator=(const ValueElement& other) { +ValueElement ValueElement::operator=(const ValueElement& other) +{ copy(other); return *this; } -QString ValueElement::getName() const { - return name; -} +QString ValueElement::getName() const { return name; } -void ValueElement::setName(const QString& value) { - name = value; -} +void ValueElement::setName(const QString& value) { name = value; } -QString ValueElement::getTopic() const { - return topic; -} +QString ValueElement::getTopic() const { return topic; } -void ValueElement::setTopic(const QString& value) { - topic = value; -} +void ValueElement::setTopic(const QString& value) { topic = value; } -QString ValueElement::getReceivedValue() const { - return receivedValue; -} +QString ValueElement::getReceivedValue() const { return receivedValue; } -void ValueElement::setReceivedValue(const QString& value) { +void ValueElement::setReceivedValue(const QString& value) +{ receivedValue = value; } -QString ValueElement::getDisplayedValue() const { - return displayedValue; -} +QString ValueElement::getDisplayedValue() const { return displayedValue; } -void ValueElement::setDisplayedValue(const QString& value) { +void ValueElement::setDisplayedValue(const QString& value) +{ displayedValue = value; } -QString ValueElement::getColor() const { - return color; -} +QString ValueElement::getColor() const { return color; } -void ValueElement::setColor(const QString& value) { - color = value; -} +void ValueElement::setColor(const QString& value) { color = value; } -QString ValueElement::toString() const { - return getName() + ": " + getTopic() + " [" + getReceivedValue() + " = " + getDisplayedValue() + "] color=" + getColor(); +QString ValueElement::toString() const +{ + return getName() + ": " + getTopic() + " [" + getReceivedValue() + " = " + + getDisplayedValue() + "] color=" + getColor(); } -XmlObject ValueElement::toXmlObject() const { +XmlObject ValueElement::toXmlObject() const +{ XmlObject obj("Rule"); obj.addAttribute("name", getName()); obj.addAttribute("topic", getTopic()); @@ -86,11 +73,14 @@ XmlObject ValueElement::toXmlObject() const { return obj; } -bool ValueElement::fromXmlObject(const XmlObject& xmlObject) { +bool ValueElement::fromXmlObject(const XmlObject& xmlObject) +{ bool result = false; - if(xmlObject.getObjectName() == "Rule" && xmlObject.hasAttribute("name")) { + if (xmlObject.getObjectName() == "Rule" && xmlObject.hasAttribute("name")) + { QString name = xmlObject.getAttribute("name"); - if(name != "") { + if (name != "") + { setName(name); result = true; } @@ -102,14 +92,17 @@ bool ValueElement::fromXmlObject(const XmlObject& xmlObject) { setOutputTopic(xmlObject.getAttribute("outputTopic")); int display = 1; - if(xmlObject.getIntAttribute("displayInView", display) && (display == 0 || display == 1)) { + if (xmlObject.getAttribute("displayInView", display) && + (display == 0 || display == 1)) + { setDisplayInView(display); } } return result; } -void ValueElement::copy(const ValueElement& other) { +void ValueElement::copy(const ValueElement& other) +{ setName(other.getName()); setTopic(other.getTopic()); setReceivedValue(other.getReceivedValue()); @@ -119,39 +112,31 @@ void ValueElement::copy(const ValueElement& other) { setDisplayInView(other.isDisplayInView()); } -bool ValueElement::isDisplayInView() const { - return displayInView; -} +bool ValueElement::isDisplayInView() const { return displayInView; } -void ValueElement::setDisplayInView(bool value) { - displayInView = value; -} +void ValueElement::setDisplayInView(bool value) { displayInView = value; } -QString ValueElement::getOutputTopic() const { - return outputTopic; -} +QString ValueElement::getOutputTopic() const { return outputTopic; } -void ValueElement::setOutputTopic(const QString& value) { - outputTopic = value; -} +void ValueElement::setOutputTopic(const QString& value) { outputTopic = value; } -bool ValueElement::isEmitActive() const { - return outputTopic != ""; -} +bool ValueElement::isEmitActive() const { return outputTopic != ""; } -QString ValueElement::getCurrentValue() const { - return currentValue; -} +QString ValueElement::getCurrentValue() const { return currentValue; } -bool ValueElement::updateCurrentValue(const QString& value) { - if(getReceivedValue() == "" || value == getReceivedValue()) { - if(getDisplayedValue() != "") { +bool ValueElement::updateCurrentValue(const QString& value) +{ + if (getReceivedValue() == "" || value == getReceivedValue()) + { + if (getDisplayedValue() != "") + { currentValue = getDisplayedValue(); - } else { + } + else + { currentValue = value; } return true; } return false; } - diff --git a/Modules/ValuesConverterViewer/valuesconverterviewermodule.cpp b/Modules/ValuesConverterViewer/valuesconverterviewermodule.cpp index 8adf3113eb150c68806b4b4061f5de5fcb912d70..21c6361ead1e1ea8ebc63b677f047a3debdbf504 100644 --- a/Modules/ValuesConverterViewer/valuesconverterviewermodule.cpp +++ b/Modules/ValuesConverterViewer/valuesconverterviewermodule.cpp @@ -1,53 +1,59 @@ #include "valuesconverterviewermodule.h" -#include "ui_valuesconverterviewermodule.h" -#include "valuesviewerconfigpanel.h" -#include "Core/modulemessagesbroker.h" #include "Core/Message/topicandfieldfilter.h" +#include "Core/modulemessagesbroker.h" +#include "ui_valuesconverterviewermodule.h" +#include "valuesviewerconfigpanel.h" -ValuesConverterViewerModule::ValuesConverterViewerModule(QWidget* parent) : DefaultModule(parent), ui(new Ui::ValuesConverterViewerModule) { +ValuesConverterViewerModule::ValuesConverterViewerModule(QWidget* parent) + : DefaultModule(parent), ui(new Ui::ValuesConverterViewerModule) +{ ui->setupUi(this); defaultContextMenuSetup(); - getCore()->getModuleMessagesBroker()->subscribe({"*"}, this, [this](const ModuleMessage & msg) { - onMsgReceived(msg); - }); + getCore()->getModuleMessagesBroker()->subscribe( + {"*"}, this, [this](const ModuleMessage& msg) { onMsgReceived(msg); }); } -ValuesConverterViewerModule::~ValuesConverterViewerModule() { +ValuesConverterViewerModule::~ValuesConverterViewerModule() +{ clearLabels(); getCore()->getModuleMessagesBroker()->unsubscribe({"*"}, this); delete ui; } +QWidget* ValuesConverterViewerModule::toWidget() { return this; } -QWidget* ValuesConverterViewerModule::toWidget() { - return this; -} - -XmlObject ValuesConverterViewerModule::toXmlObject() { +XmlObject ValuesConverterViewerModule::toXmlObject() +{ XmlObject obj(getName(ModuleId::VALUESCONVERTERVIEWER)); obj.addAttribute("Columns", QString::number(columns)); - for(int i = 0; i < rules.count(); i++) { + for (int i = 0; i < rules.count(); i++) + { obj.addChild(rules[i].toXmlObject()); } return obj; } -void ValuesConverterViewerModule::fromXmlObject(const XmlObject& xmlObject) { - if(xmlObject.getObjectName() == getName(ModuleId::VALUESCONVERTERVIEWER)) { +void ValuesConverterViewerModule::fromXmlObject(const XmlObject& xmlObject) +{ + if (xmlObject.getObjectName() == getName(ModuleId::VALUESCONVERTERVIEWER)) + { int col; - if(xmlObject.getIntAttribute("Columns", col)) { + if (xmlObject.getAttribute("Columns", col)) + { columns = col; } - for(int i = 0; i < xmlObject.childCount(); i++) { + for (int i = 0; i < xmlObject.childCount(); i++) + { XmlObject child = xmlObject.childAt(i); ValueElement el; - if(el.fromXmlObject(child)) { + if (el.fromXmlObject(child)) + { addRule(el); } } @@ -55,101 +61,129 @@ void ValuesConverterViewerModule::fromXmlObject(const XmlObject& xmlObject) { } } -void ValuesConverterViewerModule::onConfigureClicked() { +void ValuesConverterViewerModule::onConfigureClicked() +{ ValuesViewerConfigPanel* sPanel = new ValuesViewerConfigPanel(); sPanel->setRules(rules); sPanel->setColumnsCount(columns); - connect(sPanel, &ValuesViewerConfigPanel::configurationSaved, this, &ValuesConverterViewerModule::onConfigurationSaved); + connect(sPanel, &ValuesViewerConfigPanel::configurationSaved, this, + &ValuesConverterViewerModule::onConfigurationSaved); sPanel->show(); } -void ValuesConverterViewerModule::onConfigurationSaved(ValuesViewerConfigPanel* sPanel) { +void ValuesConverterViewerModule::onConfigurationSaved( + ValuesViewerConfigPanel* sPanel) +{ setRules(sPanel->getRules()); columns = sPanel->getColumnsCount(); createLabels(); } -void ValuesConverterViewerModule::addCustomActionsToMenu() { +void ValuesConverterViewerModule::addCustomActionsToMenu() +{ QAction* configure = new QAction("Configure"); - connect(configure, &QAction::triggered, this, &ValuesConverterViewerModule::onConfigureClicked); + connect(configure, &QAction::triggered, this, + &ValuesConverterViewerModule::onConfigureClicked); addActionToMenu(configure); } -QLabel* ValuesConverterViewerModule::createView(const ValueElement& el) const { +QLabel* ValuesConverterViewerModule::createView(const ValueElement& el) const +{ QLabel* label = new QLabel(); label->setText(el.getName()); label->setAlignment(Qt::AlignCenter); return label; } -void ValuesConverterViewerModule::clearLabels() { - while(labels.count() > 0) { +void ValuesConverterViewerModule::clearLabels() +{ + while (labels.count() > 0) + { QLabel* l = labels[0]; labels.removeAll(l); delete l; } } -void ValuesConverterViewerModule::createLabels() { +void ValuesConverterViewerModule::createLabels() +{ clearLabels(); - if(columns <= 0) { + if (columns <= 0) + { columns = minColNumber; } int col = 0; int row = 0; - for (int i = 0; i < rules.count(); i++ ) { + for (int i = 0; i < rules.count(); i++) + { QLabel* label; int labelIndex = findLabelIndexByName(rules[i].getName()); - if(labelIndex >= 0 && labelIndex < labels.count()) { + if (labelIndex >= 0 && labelIndex < labels.count()) + { label = labels[labelIndex]; - } else { + } + else + { label = createView(rules[i]); - if(col == columns) { + if (col == columns) + { col = 0; row++; } - if(rules[i].isDisplayInView()) { + if (rules[i].isDisplayInView()) + { ui->mainLayout_grid->addWidget(label, row, col); col++; } } labels.append(label); - } } -void ValuesConverterViewerModule::addRule(const ValueElement& el) { +void ValuesConverterViewerModule::addRule(const ValueElement& el) +{ rules.append(el); } -void ValuesConverterViewerModule::setRules(const QList<ValueElement>& rList) { +void ValuesConverterViewerModule::setRules(const QList<ValueElement>& rList) +{ clearRules(); - for (int i = 0; i < rList.count(); i++ ) { + for (int i = 0; i < rList.count(); i++) + { addRule(rList[i]); } } -void ValuesConverterViewerModule::onMsgReceived(const ModuleMessage& msg) { +void ValuesConverterViewerModule::onMsgReceived(const ModuleMessage& msg) +{ MessageField value; - for (int i = 0; i < rules.count(); i++ ) { - if(TopicAndFieldFilter::fromStringUnsafe(rules[i].getTopic()).matchMessage(msg, value)) { - if(rules[i].updateCurrentValue(value.getString())) { + for (int i = 0; i < rules.count(); i++) + { + if (TopicAndFieldFilter::fromStringUnsafe(rules[i].getTopic()) + .matchMessage(msg, value)) + { + if (rules[i].updateCurrentValue(value.getString())) + { QTime time(0, 0, 0, 0); uint64_t ms = msg.getField("timestamp").getUInteger(0); - time = time.addMSecs(ms); + time = time.addMSecs(ms); QString str = "(" + time.toString("HH:mm:ss") + ")\n"; - labels[i]->setText(rules[i].getName() + "\n" + str + rules[i].getCurrentValue()); - if(rules[i].getColor() != "") { - labels[i]->setStyleSheet("color:" + rules[i].getColor() + ";"); + labels[i]->setText(rules[i].getName() + "\n" + str + + rules[i].getCurrentValue()); + if (rules[i].getColor() != "") + { + labels[i]->setStyleSheet("color:" + rules[i].getColor() + + ";"); } - if(rules[i].isEmitActive()) { + if (rules[i].isEmitActive()) + { ModuleMessage convertedMsg(msg); convertedMsg.setField("value", rules[i].getCurrentValue()); convertedMsg.setTopic(rules[i].getOutputTopic()); @@ -160,27 +194,37 @@ void ValuesConverterViewerModule::onMsgReceived(const ModuleMessage& msg) { } } -void ValuesConverterViewerModule::clearRules() { - for (int i = 0; i < rules.count(); i++ ) { - if(rules[i].getTopic() != "") { - getCore()->getModuleMessagesBroker()->unsubscribe(rules[i].getTopic(), this); +void ValuesConverterViewerModule::clearRules() +{ + for (int i = 0; i < rules.count(); i++) + { + if (rules[i].getTopic() != "") + { + getCore()->getModuleMessagesBroker()->unsubscribe( + rules[i].getTopic(), this); } } rules.clear(); } -int ValuesConverterViewerModule::findLabelIndexByName(const QString& name) { - for (int i = 0; i < labels.count(); i++ ) { - if(labels[i]->text() == name) { +int ValuesConverterViewerModule::findLabelIndexByName(const QString& name) +{ + for (int i = 0; i < labels.count(); i++) + { + if (labels[i]->text() == name) + { return i; } } return -1; } -bool ValuesConverterViewerModule::isTopicPresent(const QString& topic) { - for (int i = 0; i < rules.count(); i++ ) { - if(rules[i].getTopic() == topic) { +bool ValuesConverterViewerModule::isTopicPresent(const QString& topic) +{ + for (int i = 0; i < rules.count(); i++) + { + if (rules[i].getTopic() == topic) + { return true; } } diff --git a/Modules/skywardhubstrings.h b/Modules/skywardhubstrings.h index d4270ebe3cfa52e1ede46f49daccdebe0592e309..6c8739ebd3d0dc814d7042bad3c4f24c1dba1f81 100644 --- a/Modules/skywardhubstrings.h +++ b/Modules/skywardhubstrings.h @@ -6,14 +6,19 @@ namespace SkywardHubStrings { -static const QString defaultConfigurationFolder = "SkywardHubConfig"; -static const QString defaultSettingsFilePath = defaultConfigurationFolder + "/" + "settings.xml"; -static const QString defaultPrefabsFolderName = "Prefabs"; -static const QString defaultLogsFolder = defaultConfigurationFolder + "/" + "Logs"; -static const QString defaultStreamFile = defaultConfigurationFolder + "/" + "StreamFile.txt"; -static const QString defaultPrefabsFolder = defaultConfigurationFolder + "/" + defaultPrefabsFolderName + "/"; +static const QString defaultConfigurationFolder = "SkywardHubConfig"; +static const QString defaultSettingsFilePath = + defaultConfigurationFolder + "/" + "settings.xml"; +static const QString defaultPrefabsFolderName = "Prefabs"; +static const QString defaultLogsFolder = + defaultConfigurationFolder + "/" + "Logs"; +static const QString defaultStreamFile = + defaultConfigurationFolder + "/" + "StreamFile.txt"; +static const QString defaultPrefabsFolder = + defaultConfigurationFolder + "/" + defaultPrefabsFolderName + "/"; static const QString defaultConfigurationFileName = "default.xml"; -static const QString defaultConfigurationIconPath = defaultConfigurationFolder + "/" + "defaultConfigIcon.svg"; +static const QString defaultConfigurationIconPath = + defaultConfigurationFolder + "/" + "defaultConfigIcon.svg"; // Xml Tags Name static const QString skywardHubInitFileTag = "LoadOnLaunch"; @@ -25,26 +30,31 @@ static const QString configurationDescriptionAttribute = "Description"; // Output Messages static const QString settingsSavedCorrectlyMsg = "Settings saved"; -static const QString serialPortClosedErrorMsg = "Mavlink >> Error, Serial port closed, impossible to write msg"; -static const QString imageViewerInfo = "Double click on a label to open the settings panel"; +static const QString serialPortClosedErrorMsg = + "Mavlink >> Error, Serial port closed, impossible to write msg"; +static const QString imageViewerInfo = + "Double click on a label to open the settings panel"; // Topics static const QString commandsTopic = "TelemetryCommand"; static const QString treeViewerReceivingBaseTopic = "TreeViewer"; -static const QString logCommandsTopic = "LogCommands"; -static const QString raw_event_id = "event_id"; -static const QString raw_event_topic_id = "topic_id"; -static const QString mavlink_orientation_tc_yaw_name = "yaw"; -static const QString mavlink_orientation_tc_pitch_name = "pitch"; -static const QString mavlink_orientation_tc_roll_name = "roll"; -static const QString mavlink_quality_link_topic = "MavlinkLinkQuality"; -static const QString mavlink_received_msg_topic = "Mav"; -static const QString mavlink_initial_coordinates_tc_latitude_name = "latitude"; -static const QString mavlink_initial_coordinates_tc_longitude_name = "longitude"; - -static const QString mavlink_received_msg_ACK_topic = mavlink_received_msg_topic + "/ACK_TM"; -static const QString mavlink_received_msg_NACK_topic = mavlink_received_msg_topic + "/NACK_TM"; +static const QString logCommandsTopic = "LogCommands"; +static const QString raw_event_id = "event_id"; +static const QString raw_event_topic_id = "topic_id"; +static const QString mavlink_orientation_tc_yaw_name = "yaw"; +static const QString mavlink_orientation_tc_pitch_name = "pitch"; +static const QString mavlink_orientation_tc_roll_name = "roll"; +static const QString mavlink_quality_link_topic = "MavlinkLinkQuality"; +static const QString mavlink_received_msg_topic = "Mav"; +static const QString mavlink_initial_coordinates_tc_latitude_name = "latitude"; +static const QString mavlink_initial_coordinates_tc_longitude_name = + "longitude"; + +static const QString mavlink_received_msg_ACK_topic = + mavlink_received_msg_topic + "/ACK_TM"; +static const QString mavlink_received_msg_NACK_topic = + mavlink_received_msg_topic + "/NACK_TM"; }; // namespace SkywardHubStrings diff --git a/SkywardHub.pro b/SkywardHub.pro index 40c31260621626001c693ee0ce75fe98dfa1aa74..bd2e71e719ca89dc814b4eb93b197b42ecff0079 100644 --- a/SkywardHub.pro +++ b/SkywardHub.pro @@ -31,6 +31,7 @@ SOURCES += \ Core/skywardhubcore.cpp \ Core/xmlobject.cpp \ Modules/CommandPad/commandpad.cpp \ + Modules/CommandPad/MessageFormElement.cpp \ Modules/DefaultModule/defaultmodule.cpp \ Modules/Empty/emptymodule.cpp \ Modules/FileStream/filestreammodule.cpp \ @@ -84,6 +85,7 @@ HEADERS += \ Core/skywardhubcore.h \ Core/xmlobject.h \ Modules/CommandPad/commandpad.h \ + Modules/CommandPad/MessageFormElement.h \ Modules/DefaultModule/defaultmodule.h \ Modules/Empty/emptymodule.h \ Modules/FileStream/filestreammodule.h \