Implement #83 with backwards compatiblity

This commit is contained in:
Alex Spataru 2021-11-23 17:50:55 -06:00
parent f9bed1ab10
commit 4d5eac980e
14 changed files with 303 additions and 295 deletions

View File

@ -40,7 +40,7 @@ Item {
// //
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: app.spacing * 2 spacing: app.spacing
anchors.margins: (app.spacing * 1.5) - 5 anchors.margins: (app.spacing * 1.5) - 5
// //

View File

@ -100,21 +100,6 @@ FramelessWindow.CustomWindow {
} }
} }
//
// Window drag handler
//
Item {
anchors.fill: parent
DragHandler {
grabPermissions: TapHandler.CanTakeOverFromAnything
onActiveChanged: {
if (active)
root.startSystemMove()
}
}
}
// //
// Window controls // Window controls
// //

View File

@ -513,7 +513,6 @@ FramelessWindow.CustomWindow {
} }
Button { Button {
checkable: true
icon.color: palette.text icon.color: palette.text
opacity: enabled ? 1 : 0.5 opacity: enabled ? 1 : 0.5
Layout.maximumWidth: height Layout.maximumWidth: height

View File

@ -25,6 +25,7 @@
#include <AppInfo.h> #include <AppInfo.h>
#include <IO/Manager.h> #include <IO/Manager.h>
#include <JSON/Generator.h> #include <JSON/Generator.h>
#include <JSON/FrameInfo.h>
#include <Misc/Utilities.h> #include <Misc/Utilities.h>
#include <Misc/TimerEvents.h> #include <Misc/TimerEvents.h>
@ -150,7 +151,7 @@ void Export::writeValues()
// Get project title & cell values // Get project title & cell values
auto dateTime = m_jsonList.first().rxDateTime; auto dateTime = m_jsonList.first().rxDateTime;
auto json = m_jsonList.first().jsonDocument.object(); auto json = m_jsonList.first().jsonDocument.object();
auto projectTitle = json.value("t").toVariant().toString(); auto projectTitle = JFI_Value(json, "title", "t").toString();
// Validate JSON & title // Validate JSON & title
if (json.isEmpty() || projectTitle.isEmpty()) if (json.isEmpty() || projectTitle.isEmpty())
@ -162,35 +163,26 @@ void Export::writeValues()
// Get cell titles & values // Get cell titles & values
StringList titles; StringList titles;
StringList values; StringList values;
auto groups = json.value("g").toArray(); auto groups = JFI_Value(json, "groups", "g").toArray();
for (int i = 0; i < groups.count(); ++i) for (int i = 0; i < groups.count(); ++i)
{ {
// Get group & dataset array // Get group & dataset array
auto group = groups.at(i).toObject(); auto group = groups.at(i).toObject();
auto datasets = group.value("d").toArray(); auto datasets = JFI_Value(group, "datasets", "d").toArray();
if (group.isEmpty() || datasets.isEmpty()) if (group.isEmpty() || datasets.isEmpty())
continue; continue;
// Get group title // Get group title
auto groupTitle = group.value("t").toVariant().toString(); auto groupTitle = JFI_Value(group, "title", "t").toVariant().toString();
// Get dataset titles & values // Get dataset titles & values
for (int j = 0; j < datasets.count(); ++j) for (int j = 0; j < datasets.count(); ++j)
{ {
// Get dataset object & fields
auto dataset = datasets.at(j).toObject(); auto dataset = datasets.at(j).toObject();
auto datasetTitle = dataset.value("t").toVariant().toString(); auto datasetTitle = JFI_Value(dataset, "title", "t").toString();
auto datasetUnits = dataset.value("u").toVariant().toString(); auto datasetUnits = JFI_Value(dataset, "units", "u").toString();
auto datasetValue = dataset.value("v").toVariant().toString(); auto datasetValue = JFI_Value(dataset, "value", "v").toString();
datasetTitle = datasetTitle.replace("\n", "");
datasetUnits = datasetUnits.replace("\n", "");
datasetValue = datasetValue.replace("\n", "");
datasetTitle = datasetTitle.replace("\r", "");
datasetUnits = datasetUnits.replace("\r", "");
datasetValue = datasetValue.replace("\r", "");
if (datasetTitle.isEmpty())
continue;
// Construct dataset title from group, dataset title & units // Construct dataset title from group, dataset title & units
QString title; QString title;

View File

@ -36,6 +36,7 @@
#include <IO/Manager.h> #include <IO/Manager.h>
#include <Misc/Utilities.h> #include <Misc/Utilities.h>
#include <JSON/Generator.h> #include <JSON/Generator.h>
#include <JSON/FrameInfo.h>
namespace CSV namespace CSV
{ {
@ -560,31 +561,35 @@ QJsonDocument Player::getJsonFrame(const int row)
// Replace JSON title // Replace JSON title
auto json = jsonTemplate.object(); auto json = jsonTemplate.object();
json["t"] = tr("Replay of %1").arg(filename()); if (json.contains("t"))
json["t"] = tr("Replay of %1").arg(filename());
else
json["title"] = tr("Replay of %1").arg(filename());
// Replace values in JSON with values in row using the model. // Replace values in JSON with values in row using the model.
// This is very ugly code, somebody please fix it :( // This is very ugly code, somebody please fix it :(
auto groups = json.value("g").toArray(); auto groups = JFI_Value(json, "groups", "g").toArray();
foreach (auto groupKey, m_model.keys()) foreach (auto groupKey, m_model.keys())
{ {
for (int i = 0; i < groups.count(); ++i) for (int i = 0; i < groups.count(); ++i)
{ {
auto group = groups.at(i).toObject(); auto group = groups.at(i).toObject();
if (group.value("t") == groupKey) if (JFI_Value(group, "title", "t") == groupKey)
{ {
auto datasetKeys = m_model.value(groupKey); auto datasetKeys = m_model.value(groupKey);
auto datasets = group.value("d").toArray(); auto datasets = JFI_Value(group, "datasets", "d").toArray();
foreach (auto datasetKey, datasetKeys) foreach (auto datasetKey, datasetKeys)
{ {
for (int j = 0; j < datasets.count(); ++j) for (int j = 0; j < datasets.count(); ++j)
{ {
auto dataset = datasets.at(j).toObject(); auto dataset = datasets.at(j).toObject();
if (dataset.value("t") == datasetKey) if (JFI_Value(dataset, "title", "t") == datasetKey)
{ {
auto value = values.at(getDatasetIndex(groupKey, datasetKey)); auto value = values.at(getDatasetIndex(groupKey, datasetKey));
dataset.remove("v"); dataset.remove("v");
dataset.insert("v", value); dataset.remove("value");
dataset.insert("value", value);
} }
datasets.replace(j, dataset); datasets.replace(j, dataset);
@ -592,7 +597,8 @@ QJsonDocument Player::getJsonFrame(const int row)
} }
group.remove("d"); group.remove("d");
group.insert("d", datasets); group.remove("datasets");
group.insert("datasets", datasets);
} }
groups.replace(i, group); groups.replace(i, group);
@ -601,7 +607,8 @@ QJsonDocument Player::getJsonFrame(const int row)
// Update groups from JSON // Update groups from JSON
json.remove("g"); json.remove("g");
json.insert("g", groups); json.remove("groups");
json.insert("groups", groups);
// Return new JSON document // Return new JSON document
return QJsonDocument(json); return QJsonDocument(json);

View File

@ -22,10 +22,10 @@
#include "Dataset.h" #include "Dataset.h"
#include "Generator.h" #include "Generator.h"
#include "FrameInfo.h"
namespace JSON namespace JSON
{ {
Dataset::Dataset(QObject *parent) Dataset::Dataset(QObject *parent)
: QObject(parent) : QObject(parent)
, m_fft(false) , m_fft(false)
@ -156,37 +156,20 @@ QJsonObject Dataset::jsonData() const
*/ */
bool Dataset::read(const QJsonObject &object) bool Dataset::read(const QJsonObject &object)
{ {
static QJSEngine JAVASCRIPT_ENGINE;
if (!object.isEmpty()) if (!object.isEmpty())
{ {
auto fft = object.value("fft").toVariant().toBool(); auto fft = JFI_Value(object, "fft").toBool();
auto led = object.value("led").toVariant().toBool(); auto led = JFI_Value(object, "led").toBool();
auto log = object.value("log").toVariant().toBool(); auto log = JFI_Value(object, "log").toBool();
auto graph = object.value("g").toVariant().toBool(); auto min = JFI_Value(object, "min").toString();
auto title = object.value("t").toVariant().toString(); auto max = JFI_Value(object, "max").toString();
auto value = object.value("v").toVariant().toString(); auto alarm = JFI_Value(object, "alarm").toString();
auto units = object.value("u").toVariant().toString(); auto graph = JFI_Value(object, "graph", "g").toBool();
auto widget = object.value("w").toVariant().toString(); auto title = JFI_Value(object, "title", "t").toString();
auto min = object.value("min").toVariant().toString(); auto value = JFI_Value(object, "value", "v").toString();
auto max = object.value("max").toVariant().toString(); auto units = JFI_Value(object, "units", "u").toString();
auto alarm = object.value("alarm").toVariant().toString(); auto widget = JFI_Value(object, "widget", "w").toString();
auto fftSamples = object.value("fftSamples").toVariant().toInt(); auto fftSamples = JFI_Value(object, "fftSamples").toInt();
min = min.replace("\n", "");
min = min.replace("\r", "");
max = max.replace("\n", "");
max = max.replace("\r", "");
title = title.replace("\n", "");
title = title.replace("\r", "");
value = value.replace("\n", "");
value = value.replace("\r", "");
units = units.replace("\n", "");
units = units.replace("\r", "");
alarm = alarm.replace("\n", "");
alarm = alarm.replace("\r", "");
widget = widget.replace("\n", "");
widget = widget.replace("\r", "");
if (!value.isEmpty() && !title.isEmpty()) if (!value.isEmpty() && !title.isEmpty())
{ {

View File

@ -21,6 +21,7 @@
*/ */
#include "Editor.h" #include "Editor.h"
#include "FrameInfo.h"
#include "Generator.h" #include "Generator.h"
#include "IO/Manager.h" #include "IO/Manager.h"
#include "Misc/Utilities.h" #include "Misc/Utilities.h"
@ -302,10 +303,10 @@ bool Editor::saveJsonFile()
// Create JSON document & add properties // Create JSON document & add properties
QJsonObject json; QJsonObject json;
json.insert("t", title()); json.insert("title", title());
json.insert("s", separator()); json.insert("separator", separator());
json.insert("fe", frameEndSequence()); json.insert("frameEnd", frameEndSequence());
json.insert("fs", frameStartSequence()); json.insert("frameStart", frameStartSequence());
// Create group array // Create group array
QJsonArray groups; QJsonArray groups;
@ -313,8 +314,8 @@ bool Editor::saveJsonFile()
{ {
// Create group // Create group
QJsonObject group; QJsonObject group;
group.insert("t", groupTitle(i)); group.insert("title", groupTitle(i));
group.insert("w", groupWidget(i)); group.insert("widget", groupWidget(i));
// Create dataset array // Create dataset array
QJsonArray datasets; QJsonArray datasets;
@ -322,30 +323,30 @@ bool Editor::saveJsonFile()
{ {
// Create dataset // Create dataset
QJsonObject dataset; QJsonObject dataset;
dataset.insert("t", datasetTitle(i, j));
dataset.insert("u", datasetUnits(i, j));
dataset.insert("g", datasetGraph(i, j));
dataset.insert("led", datasetLED(i, j)); dataset.insert("led", datasetLED(i, j));
dataset.insert("w", datasetWidget(i, j));
dataset.insert("fft", datasetFftPlot(i, j)); dataset.insert("fft", datasetFftPlot(i, j));
dataset.insert("log", datasetLogPlot(i, j)); dataset.insert("log", datasetLogPlot(i, j));
dataset.insert("v", "%" + QString::number(datasetIndex(i, j))); dataset.insert("title", datasetTitle(i, j));
dataset.insert("units", datasetUnits(i, j));
dataset.insert("graph", datasetGraph(i, j));
dataset.insert("widget", datasetWidget(i, j));
dataset.insert("min", datasetWidgetMin(i, j).toDouble()); dataset.insert("min", datasetWidgetMin(i, j).toDouble());
dataset.insert("max", datasetWidgetMax(i, j).toDouble()); dataset.insert("max", datasetWidgetMax(i, j).toDouble());
dataset.insert("alarm", datasetWidgetAlarm(i, j).toDouble()); dataset.insert("alarm", datasetWidgetAlarm(i, j).toDouble());
dataset.insert("fftSamples", datasetFFTSamples(i, j).toInt()); dataset.insert("fftSamples", datasetFFTSamples(i, j).toInt());
dataset.insert("value", "%" + QString::number(datasetIndex(i, j)));
// Add dataset to array // Add dataset to array
datasets.append(dataset); datasets.append(dataset);
} }
// Add datasets to group // Add datasets to group
group.insert("d", datasets); group.insert("datasets", datasets);
groups.append(group); groups.append(group);
} }
// Add groups array to JSON // Add groups array to JSON
json.insert("g", groups); json.insert("groups", groups);
// Write JSON data to file // Write JSON data to file
file.write(QJsonDocument(json).toJson(QJsonDocument::Indented)); file.write(QJsonDocument(json).toJson(QJsonDocument::Indented));
@ -740,10 +741,10 @@ void Editor::openJsonFile(const QString &path)
// Read data from JSON document // Read data from JSON document
auto json = document.object(); auto json = document.object();
setTitle(json.value("t").toString()); setTitle(JFI_Value(json, "title", "t").toString());
setSeparator(json.value("s").toString()); setSeparator(JFI_Value(json, "separator", "s").toString());
setFrameEndSequence(json.value("fe").toString()); setFrameEndSequence(JFI_Value(json, "frameEnd", "fe").toString());
setFrameStartSequence(json.value("fs").toString()); setFrameStartSequence(JFI_Value(json, "frameStart", "fs").toString());
// Modify IO manager settings // Modify IO manager settings
auto manager = IO::Manager::getInstance(); auto manager = IO::Manager::getInstance();
@ -755,48 +756,47 @@ void Editor::openJsonFile(const QString &path)
JSON::Generator::getInstance()->setOperationMode(JSON::Generator::kManual); JSON::Generator::getInstance()->setOperationMode(JSON::Generator::kManual);
// Read groups from JSON document // Read groups from JSON document
auto groups = json.value("g").toArray(); auto groups = JFI_Value(json, "groups", "g").toArray();
for (int group = 0; group < groups.count(); ++group) for (int g = 0; g < groups.count(); ++g)
{ {
// Get JSON group data // Get JSON group data
auto jsonGroup = groups.at(group).toObject(); auto group = groups.at(g).toObject();
// Register group with C++ model // Register group with C++ model
addGroup(); addGroup();
setGroupTitle(group, jsonGroup.value("t").toString()); setGroupTitle(g, JFI_Value(group, "title", "t").toString());
setGroupWidgetData(group, jsonGroup.value("w").toString()); setGroupWidgetData(g, JFI_Value(group, "widget", "w").toString());
// Get JSON group datasets // Get JSON group datasets
auto jsonDatasets = jsonGroup.value("d").toArray(); auto datasets = JFI_Value(group, "datasets", "d").toArray();
for (int dataset = 0; dataset < jsonDatasets.count(); ++dataset) for (int d = 0; d < datasets.count(); ++d)
{ {
// Get dataset JSON data // Get dataset JSON data
auto jsonDataset = jsonDatasets.at(dataset).toObject(); auto dataset = datasets.at(d).toObject();
// Register dataset with C++ model // Register dataset with C++ model
addDataset(group); addDataset(g);
setDatasetGraph(group, dataset, jsonDataset.value("g").toBool()); setDatasetLED(g, d, JFI_Value(dataset, "led").toBool());
setDatasetLED(group, dataset, jsonDataset.value("led").toBool()); setDatasetFftPlot(g, d, JFI_Value(dataset, "fft").toBool());
setDatasetTitle(group, dataset, jsonDataset.value("t").toString()); setDatasetLogPlot(g, d, JFI_Value(dataset, "log").toBool());
setDatasetUnits(group, dataset, jsonDataset.value("u").toString()); setDatasetGraph(g, d, JFI_Value(dataset, "graph", "g").toBool());
setDatasetFftPlot(group, dataset, jsonDataset.value("fft").toBool()); setDatasetTitle(g, d, JFI_Value(dataset, "title", "t").toString());
setDatasetLogPlot(group, dataset, jsonDataset.value("log").toBool()); setDatasetUnits(g, d, JFI_Value(dataset, "units", "u").toString());
setDatasetWidgetData(group, dataset, jsonDataset.value("w").toString()); setDatasetFFTSamples(g, d, JFI_Value(dataset, "fftSamples").toString());
setDatasetFFTSamples( setDatasetWidgetData(g, d, JFI_Value(dataset, "widget", "w").toString());
group, dataset, QString::number(jsonDataset.value("fftSamples").toInt()));
// Get max/min texts // Get max/min texts
auto min = jsonDataset.value("min").toDouble(); auto min = JFI_Value(dataset, "min").toDouble();
auto max = jsonDataset.value("max").toDouble(); auto max = JFI_Value(dataset, "max").toDouble();
auto alarm = jsonDataset.value("alarm").toDouble(); auto alarm = JFI_Value(dataset, "alarm").toDouble();
setDatasetWidgetMin(group, dataset, QString::number(min)); setDatasetWidgetMin(g, d, QString::number(min));
setDatasetWidgetMax(group, dataset, QString::number(max)); setDatasetWidgetMax(g, d, QString::number(max));
setDatasetWidgetAlarm(group, dataset, QString::number(alarm)); setDatasetWidgetAlarm(g, d, QString::number(alarm));
// Calculate dataset index // Calculate dataset index
auto index = jsonDataset.value("v").toString(); auto index = JFI_Value(dataset, "value", "v").toString();
index.replace("%", ""); index.replace("%", "");
setDatasetIndex(group, dataset, index.toInt()); setDatasetIndex(g, d, index.toInt());
} }
} }

View File

@ -21,6 +21,7 @@
*/ */
#include "Frame.h" #include "Frame.h"
#include "FrameInfo.h"
namespace JSON namespace JSON
{ {
@ -91,12 +92,8 @@ bool Frame::read(const QJsonObject &object)
clear(); clear();
// Get title & groups array // Get title & groups array
auto title = object.value("t").toString(); auto title = JFI_Value(object, "title", "t").toString();
auto groups = object.value("g").toArray(); auto groups = JFI_Value(object, "groups", "g").toArray();
// Remove line breaks from title
title = title.replace("\n", "");
title = title.replace("\r", "");
// We need to have a project title and at least one group // We need to have a project title and at least one group
if (!title.isEmpty() && !groups.isEmpty()) if (!title.isEmpty() && !groups.isEmpty())

View File

@ -71,3 +71,34 @@ JFI_Object JFI_CreateNew(const quint64 n, const QDateTime &t, const QJsonDocumen
info.jsonDocument = d; info.jsonDocument = d;
return info; return info;
} }
/**
* Obtains the value of the first element that corresponds to given @a key
*/
QJsonValue JFI_Value(const QJsonObject &object, const QString key)
{
return JFI_Value(object, StringList { key });
}
/**
* Obtains the value of the first element that matches one of the given @a keys
*/
QJsonValue JFI_Value(const QJsonObject &object, const StringList keys)
{
for (int i = 0; i < keys.count(); ++i)
{
auto tag = keys.at(i);
if (object.contains(tag))
return object.value(tag);
}
return QJsonValue();
}
/**
* Obtains the value of the first element that corresponds to key @c a or key @c b
*/
QJsonValue JFI_Value(const QJsonObject &object, const QString a, const QString b)
{
return JFI_Value(object, StringList { a, b });
}

View File

@ -24,8 +24,13 @@
#include <QVector> #include <QVector>
#include <QDateTime> #include <QDateTime>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include "DataTypes.h"
typedef struct typedef struct
{ {
quint64 frameNumber; quint64 frameNumber;
@ -38,3 +43,7 @@ extern void JFI_SortList(QVector<JFI_Object> *list);
extern JFI_Object JFI_Empty(const quint64 n = 0); extern JFI_Object JFI_Empty(const quint64 n = 0);
extern JFI_Object JFI_CreateNew(const quint64 n, const QDateTime &t, extern JFI_Object JFI_CreateNew(const quint64 n, const QDateTime &t,
const QJsonDocument &d); const QJsonDocument &d);
extern QJsonValue JFI_Value(const QJsonObject &object, const QString key);
extern QJsonValue JFI_Value(const QJsonObject &object, const StringList keys);
extern QJsonValue JFI_Value(const QJsonObject &object, const QString a, const QString b);

View File

@ -22,6 +22,7 @@
#include "Editor.h" #include "Editor.h"
#include "Generator.h" #include "Generator.h"
#include "FrameInfo.h"
#include <CSV/Player.h> #include <CSV/Player.h>
#include <IO/Manager.h> #include <IO/Manager.h>
@ -354,19 +355,19 @@ void Generator::processFrame(const QByteArray &data, const quint64 frame,
// Calculate dynamically generated values // Calculate dynamically generated values
auto root = jsonDocument.object(); auto root = jsonDocument.object();
auto groups = root.value("g").toArray(); auto groups = JFI_Value(root, "groups", "g").toArray();
for (int i = 0; i < groups.count(); ++i) for (int i = 0; i < groups.count(); ++i)
{ {
// Get group // Get group
auto group = groups.at(i).toObject(); auto group = groups.at(i).toObject();
// Evaluate each dataset of the current group // Evaluate each dataset of the current group
auto datasets = group.value("d").toArray(); auto datasets = JFI_Value(group, "datasets", "d").toArray();
for (int j = 0; j < datasets.count(); ++j) for (int j = 0; j < datasets.count(); ++j)
{ {
// Get dataset object & value // Get dataset object & value
auto dataset = datasets.at(j).toObject(); auto dataset = datasets.at(j).toObject();
auto value = dataset.value("v").toString(); auto value = JFI_Value(root, "value", "v").toString();
// Evaluate code in dataset value (if any) // Evaluate code in dataset value (if any)
auto jsValue = m_engine.evaluate(value); auto jsValue = m_engine.evaluate(value);
@ -375,20 +376,23 @@ void Generator::processFrame(const QByteArray &data, const quint64 frame,
if (!jsValue.isError()) if (!jsValue.isError())
{ {
dataset.remove("v"); dataset.remove("v");
dataset.insert("v", jsValue.toString()); dataset.remove("value");
dataset.insert("value", jsValue.toString());
datasets.replace(j, dataset); datasets.replace(j, dataset);
} }
} }
// Replace group datasets // Replace group datasets
group.remove("d"); group.remove("d");
group.insert("d", datasets); group.remove("datasets");
group.insert("datasets", datasets);
groups.replace(i, group); groups.replace(i, group);
} }
// Replace root document group objects // Replace root document group objects
root.remove("g"); root.remove("g");
root.insert("g", groups); root.remove("groups");
root.insert("groups", groups);
// Create JSON document // Create JSON document
document = QJsonDocument(root); document = QJsonDocument(root);
@ -453,19 +457,19 @@ void JSONWorker::process()
// Calculate dynamically generated values // Calculate dynamically generated values
auto root = jsonDocument.object(); auto root = jsonDocument.object();
auto groups = root.value("g").toArray(); auto groups = JFI_Value(root, "groups", "g").toArray();
for (int i = 0; i < groups.count(); ++i) for (int i = 0; i < groups.count(); ++i)
{ {
// Get group // Get group
auto group = groups.at(i).toObject(); auto group = groups.at(i).toObject();
// Evaluate each dataset of the current group // Evaluate each dataset of the current group
auto datasets = group.value("d").toArray(); auto datasets = JFI_Value(group, "datasets", "d").toArray();
for (int j = 0; j < datasets.count(); ++j) for (int j = 0; j < datasets.count(); ++j)
{ {
// Get dataset object & value // Get dataset object & value
auto dataset = datasets.at(j).toObject(); auto dataset = datasets.at(j).toObject();
auto value = dataset.value("v").toString(); auto value = JFI_Value(root, "value", "v").toString();
// Evaluate code in dataset value (if any) // Evaluate code in dataset value (if any)
auto jsValue = m_engine->evaluate(value); auto jsValue = m_engine->evaluate(value);
@ -474,20 +478,23 @@ void JSONWorker::process()
if (!jsValue.isError()) if (!jsValue.isError())
{ {
dataset.remove("v"); dataset.remove("v");
dataset.insert("v", jsValue.toString()); dataset.remove("value");
dataset.insert("value", jsValue.toString());
datasets.replace(j, dataset); datasets.replace(j, dataset);
} }
} }
// Replace group datasets // Replace group datasets
group.remove("d"); group.remove("d");
group.insert("d", datasets); group.remove("datasets");
group.insert("datasets", datasets);
groups.replace(i, group); groups.replace(i, group);
} }
// Replace root document group objects // Replace root document group objects
root.remove("g"); root.remove("g");
root.insert("g", groups); root.remove("groups");
root.insert("groups", groups);
// Create JSON document // Create JSON document
document = QJsonDocument(root); document = QJsonDocument(root);

View File

@ -22,6 +22,7 @@
#include "Group.h" #include "Group.h"
#include "Dataset.h" #include "Dataset.h"
#include "FrameInfo.h"
namespace JSON namespace JSON
{ {
@ -97,14 +98,9 @@ bool Group::read(const QJsonObject &object)
{ {
if (!object.isEmpty()) if (!object.isEmpty())
{ {
auto array = object.value("d").toArray(); auto title = JFI_Value(object, "title", "t").toString();
auto title = object.value("t").toVariant().toString(); auto array = JFI_Value(object, "datasets", "d").toArray();
auto widget = object.value("w").toVariant().toString(); auto widget = JFI_Value(object, "widget", "w").toString();
title = title.replace("\n", "");
title = title.replace("\r", "");
widget = widget.replace("\n", "");
widget = widget.replace("\r", "");
if (!title.isEmpty() && !array.isEmpty()) if (!title.isEmpty() && !array.isEmpty())
{ {

View File

@ -126,15 +126,15 @@ int Client::mqttVersion() const
{ {
switch (m_client.version()) switch (m_client.version())
{ {
case QMQTT::V3_1_0: case QMQTT::V3_1_0:
return 0; return 0;
break; break;
case QMQTT::V3_1_1: case QMQTT::V3_1_1:
return 1; return 1;
break; break;
default: default:
return -1; return -1;
break; break;
} }
} }
@ -254,8 +254,9 @@ StringList Client::mqttVersions() const
*/ */
StringList Client::sslProtocols() const StringList Client::sslProtocols() const
{ {
return StringList { tr("System default"), "TLS v1.0", "TLS v1.1", "TLS v1.2 (or later)", return StringList { tr("System default"), "TLS v1.0", "TLS v1.1",
"DTLS v1.0", "DTLS v1.2", "DTLS v1.2 (or later)" }; "TLS v1.2 (or later)", "DTLS v1.0", "DTLS v1.2",
"DTLS v1.2 (or later)" };
} }
/** /**
@ -270,14 +271,11 @@ StringList Client::certificateModes() const
* Prompts the user to select a *.ca file and loads the certificate * Prompts the user to select a *.ca file and loads the certificate
* into the SSL configuration. * into the SSL configuration.
*/ */
void Client::loadCaFile() { void Client::loadCaFile()
{
// Prompt user to select a CA file // Prompt user to select a CA file
auto path = QFileDialog::getOpenFileName( auto path = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Select CA file"),
Q_NULLPTR, QDir::homePath(), "*.ca");
tr("Select CA file"),
QDir::homePath(),
"*.ca"
);
// Try to load the *.ca file // Try to load the *.ca file
loadCaFile(path); loadCaFile(path);
@ -382,7 +380,8 @@ void Client::setTopic(const QString &topic)
* Reads the CA file in the given @a path and loads it into the * Reads the CA file in the given @a path and loads it into the
* SSL configuration handler for the MQTT connection. * SSL configuration handler for the MQTT connection.
*/ */
void Client::loadCaFile(const QString &path) { void Client::loadCaFile(const QString &path)
{
// Empty path, abort // Empty path, abort
if (path.isEmpty()) if (path.isEmpty())
return; return;
@ -390,15 +389,16 @@ void Client::loadCaFile(const QString &path) {
// Try to read file contents // Try to read file contents
QByteArray data; QByteArray data;
QFile file(path); QFile file(path);
if (file.open(QFile::ReadOnly)) { if (file.open(QFile::ReadOnly))
{
data = file.readAll(); data = file.readAll();
file.close(); file.close();
} }
// Read error, alert user // Read error, alert user
else { else
Misc::Utilities::showMessageBox(tr("Cannot open CA file!"), {
file.errorString()); Misc::Utilities::showMessageBox(tr("Cannot open CA file!"), file.errorString());
file.close(); file.close();
return; return;
} }
@ -412,31 +412,33 @@ void Client::loadCaFile(const QString &path) {
/** /**
* Changes the SSL protocol version to use for the MQTT connection. * Changes the SSL protocol version to use for the MQTT connection.
*/ */
void Client::setSslProtocol(const int index) { void Client::setSslProtocol(const int index)
switch (index) { {
case 0: switch (index)
m_sslConfiguration.setProtocol(QSsl::SecureProtocols); {
break; case 0:
case 1: m_sslConfiguration.setProtocol(QSsl::SecureProtocols);
m_sslConfiguration.setProtocol(QSsl::TlsV1_0); break;
break; case 1:
case 2: m_sslConfiguration.setProtocol(QSsl::TlsV1_0);
m_sslConfiguration.setProtocol(QSsl::TlsV1_1); break;
break; case 2:
case 3: m_sslConfiguration.setProtocol(QSsl::TlsV1_1);
m_sslConfiguration.setProtocol(QSsl::TlsV1_3OrLater); break;
break; case 3:
case 4: m_sslConfiguration.setProtocol(QSsl::TlsV1_3OrLater);
m_sslConfiguration.setProtocol(QSsl::DtlsV1_0); break;
break; case 4:
case 5: m_sslConfiguration.setProtocol(QSsl::DtlsV1_0);
m_sslConfiguration.setProtocol(QSsl::DtlsV1_2); break;
break; case 5:
case 6: m_sslConfiguration.setProtocol(QSsl::DtlsV1_2);
m_sslConfiguration.setProtocol(QSsl::DtlsV1_2OrLater); break;
break; case 6:
default: m_sslConfiguration.setProtocol(QSsl::DtlsV1_2OrLater);
break; break;
default:
break;
} }
emit sslProtocolChanged(); emit sslProtocolChanged();
@ -463,8 +465,8 @@ void Client::setSslEnabled(const bool enabled)
*/ */
void Client::setCertificateMode(const int index) void Client::setCertificateMode(const int index)
{ {
switch (index) { switch (index)
{
} }
emit certificateModeChanged(); emit certificateModeChanged();
@ -506,14 +508,14 @@ void Client::setMqttVersion(const int versionIndex)
{ {
switch (versionIndex) switch (versionIndex)
{ {
case 0: case 0:
m_client.setVersion(QMQTT::V3_1_0); m_client.setVersion(QMQTT::V3_1_0);
break; break;
case 1: case 1:
m_client.setVersion(QMQTT::V3_1_1); m_client.setVersion(QMQTT::V3_1_1);
break; break;
default: default:
break; break;
} }
emit mqttVersionChanged(); emit mqttVersionChanged();
@ -595,99 +597,99 @@ void Client::onError(const QMQTT::ClientError error)
switch (error) switch (error)
{ {
case QMQTT::UnknownError: case QMQTT::UnknownError:
str = tr("Unknown error"); str = tr("Unknown error");
break; break;
case QMQTT::SocketConnectionRefusedError: case QMQTT::SocketConnectionRefusedError:
str = tr("Connection refused"); str = tr("Connection refused");
break; break;
case QMQTT::SocketRemoteHostClosedError: case QMQTT::SocketRemoteHostClosedError:
str = tr("Remote host closed the connection"); str = tr("Remote host closed the connection");
break; break;
case QMQTT::SocketHostNotFoundError: case QMQTT::SocketHostNotFoundError:
str = tr("Host not found"); str = tr("Host not found");
break; break;
case QMQTT::SocketAccessError: case QMQTT::SocketAccessError:
str = tr("Socket access error"); str = tr("Socket access error");
break; break;
case QMQTT::SocketResourceError: case QMQTT::SocketResourceError:
str = tr("Socket resource error"); str = tr("Socket resource error");
break; break;
case QMQTT::SocketTimeoutError: case QMQTT::SocketTimeoutError:
str = tr("Socket timeout"); str = tr("Socket timeout");
break; break;
case QMQTT::SocketDatagramTooLargeError: case QMQTT::SocketDatagramTooLargeError:
str = tr("Socket datagram too large"); str = tr("Socket datagram too large");
break; break;
case QMQTT::SocketNetworkError: case QMQTT::SocketNetworkError:
str = tr("Network error"); str = tr("Network error");
break; break;
case QMQTT::SocketAddressInUseError: case QMQTT::SocketAddressInUseError:
str = tr("Address in use"); str = tr("Address in use");
break; break;
case QMQTT::SocketAddressNotAvailableError: case QMQTT::SocketAddressNotAvailableError:
str = tr("Address not available"); str = tr("Address not available");
break; break;
case QMQTT::SocketUnsupportedSocketOperationError: case QMQTT::SocketUnsupportedSocketOperationError:
str = tr("Unsupported socket operation"); str = tr("Unsupported socket operation");
break; break;
case QMQTT::SocketUnfinishedSocketOperationError: case QMQTT::SocketUnfinishedSocketOperationError:
str = tr("Unfinished socket operation"); str = tr("Unfinished socket operation");
break; break;
case QMQTT::SocketProxyAuthenticationRequiredError: case QMQTT::SocketProxyAuthenticationRequiredError:
str = tr("Proxy authentication required"); str = tr("Proxy authentication required");
break; break;
case QMQTT::SocketSslHandshakeFailedError: case QMQTT::SocketSslHandshakeFailedError:
str = tr("SSL handshake failed"); str = tr("SSL handshake failed");
break; break;
case QMQTT::SocketProxyConnectionRefusedError: case QMQTT::SocketProxyConnectionRefusedError:
str = tr("Proxy connection refused"); str = tr("Proxy connection refused");
break; break;
case QMQTT::SocketProxyConnectionClosedError: case QMQTT::SocketProxyConnectionClosedError:
str = tr("Proxy connection closed"); str = tr("Proxy connection closed");
break; break;
case QMQTT::SocketProxyConnectionTimeoutError: case QMQTT::SocketProxyConnectionTimeoutError:
str = tr("Proxy connection timeout"); str = tr("Proxy connection timeout");
break; break;
case QMQTT::SocketProxyNotFoundError: case QMQTT::SocketProxyNotFoundError:
str = tr("Proxy not found"); str = tr("Proxy not found");
break; break;
case QMQTT::SocketProxyProtocolError: case QMQTT::SocketProxyProtocolError:
str = tr("Proxy protocol error"); str = tr("Proxy protocol error");
break; break;
case QMQTT::SocketOperationError: case QMQTT::SocketOperationError:
str = tr("Operation error"); str = tr("Operation error");
break; break;
case QMQTT::SocketSslInternalError: case QMQTT::SocketSslInternalError:
str = tr("SSL internal error"); str = tr("SSL internal error");
break; break;
case QMQTT::SocketSslInvalidUserDataError: case QMQTT::SocketSslInvalidUserDataError:
str = tr("Invalid SSL user data"); str = tr("Invalid SSL user data");
break; break;
case QMQTT::SocketTemporaryError: case QMQTT::SocketTemporaryError:
str = tr("Socket temprary error"); str = tr("Socket temprary error");
break; break;
case QMQTT::MqttUnacceptableProtocolVersionError: case QMQTT::MqttUnacceptableProtocolVersionError:
str = tr("Unacceptable MQTT protocol"); str = tr("Unacceptable MQTT protocol");
break; break;
case QMQTT::MqttIdentifierRejectedError: case QMQTT::MqttIdentifierRejectedError:
str = tr("MQTT identifier rejected"); str = tr("MQTT identifier rejected");
break; break;
case QMQTT::MqttServerUnavailableError: case QMQTT::MqttServerUnavailableError:
str = tr("MQTT server unavailable"); str = tr("MQTT server unavailable");
break; break;
case QMQTT::MqttBadUserNameOrPasswordError: case QMQTT::MqttBadUserNameOrPasswordError:
str = tr("Bad MQTT username or password"); str = tr("Bad MQTT username or password");
break; break;
case QMQTT::MqttNotAuthorizedError: case QMQTT::MqttNotAuthorizedError:
str = tr("MQTT authorization error"); str = tr("MQTT authorization error");
break; break;
case QMQTT::MqttNoPingResponse: case QMQTT::MqttNoPingResponse:
str = tr("MQTT no ping response"); str = tr("MQTT no ping response");
break; break;
default: default:
str = ""; str = "";
break; break;
} }
if (!str.isEmpty()) if (!str.isEmpty())

View File

@ -50,10 +50,10 @@ enum MQTTClientMode
* Implements a simple MQTT client, which allows Serial Studio to upload received frames * Implements a simple MQTT client, which allows Serial Studio to upload received frames
* to a MQTT broker so that other devices and/or services can make use of that * to a MQTT broker so that other devices and/or services can make use of that
* information. By acting as a MQTT subscriber, Serial Studio can display & process frames * information. By acting as a MQTT subscriber, Serial Studio can display & process frames
* from a remote Serial Studio instance. As you might notice, this has a lot of * from a remote Serial Studio instance that is setup as a MQTT publisher. As you might
* interesting applications. * notice, this has a lot of interesting applications.
* *
* For example, you can receive frames from a CanSat mission and display them allmost in * For example, you can receive frames from a CanSat mission and display them almost in
* real-time in another location, such as the "ground control" centre or by the media team * real-time in another location, such as the "ground control" centre or by the media team
* which streams the GCS display on the internet as the mission is developing. * which streams the GCS display on the internet as the mission is developing.
*/ */