mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-31 17:42:55 +08:00
Fix UTF-8 issue with CSV files opened in Excel
This commit is contained in:
parent
d2690de4f9
commit
cf839fd8e7
@ -42,6 +42,8 @@ Widgets.Window {
|
|||||||
//
|
//
|
||||||
Settings {
|
Settings {
|
||||||
category: "Device Manager"
|
category: "Device Manager"
|
||||||
|
property alias dmAuto: commAuto.checked
|
||||||
|
property alias dmManual: commManual.checked
|
||||||
property alias dmParity: parity.currentIndex
|
property alias dmParity: parity.currentIndex
|
||||||
property alias dmStopBits: stopBits.currentIndex
|
property alias dmStopBits: stopBits.currentIndex
|
||||||
property alias dmBaudRate: baudRate.currentIndex
|
property alias dmBaudRate: baudRate.currentIndex
|
||||||
|
@ -30,5 +30,9 @@ import Dataset 1.0
|
|||||||
import "../Widgets"
|
import "../Widgets"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
AccelerometerDelegate {
|
||||||
|
width: 250
|
||||||
|
height: 250
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,15 +127,10 @@ Page {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Components.WidgetGrid {
|
||||||
|
id: widgetGrid
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
Widgets.MapDelegate {
|
|
||||||
id: gpsMap
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: app.spacing * 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,91 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.0
|
||||||
|
|
||||||
Item {
|
import Group 1.0
|
||||||
|
import Dataset 1.0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: accel
|
||||||
|
spacing: app.spacing
|
||||||
|
|
||||||
|
//
|
||||||
|
// Custom properties
|
||||||
|
//
|
||||||
|
property int index: 0
|
||||||
|
property real accX: 0
|
||||||
|
property real accY: 0
|
||||||
|
property real accZ: 0
|
||||||
|
property string title: ""
|
||||||
|
property real meanGForce: 0
|
||||||
|
property real gConstant: 9.80665
|
||||||
|
|
||||||
|
//
|
||||||
|
// Calculates the mean g force for all three axes using the pythagorean theorem
|
||||||
|
//
|
||||||
|
function calculateMeanGForce() {
|
||||||
|
if (CppWidgets.accelerometerGroupCount() > accel.index) {
|
||||||
|
accel.accX = CppWidgets.accelerometerX(accel.index)
|
||||||
|
accel.accY = CppWidgets.accelerometerY(accel.index)
|
||||||
|
accel.accZ = CppWidgets.accelerometerZ(accel.index)
|
||||||
|
accel.title = CppWidgets.accelerometerGroupAt(accel.index).title
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
accel.accX = 0
|
||||||
|
accel.accY = 0
|
||||||
|
accel.accZ = 0
|
||||||
|
accel.title = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var gX = accel.accX / accel.gConstant
|
||||||
|
var gY = accel.accY / accel.gConstant
|
||||||
|
var gZ = accel.accZ / accel.gConstant
|
||||||
|
|
||||||
|
accel.meanGForce = Math.sqrt(Math.pow(gX, 2) + Math.pow(gY, 2) + Math.pow(gZ, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Accelerometer circle
|
||||||
|
//
|
||||||
|
Rectangle {
|
||||||
|
width: height
|
||||||
|
color: "#444"
|
||||||
|
border.width: 2
|
||||||
|
radius: width / 2
|
||||||
|
border.color: "#bebebe"
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Indicator controls
|
||||||
|
//
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: app.spacing
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
LED {
|
||||||
|
onColor: "#f00"
|
||||||
|
text: qsTr("Cont. value")
|
||||||
|
}
|
||||||
|
|
||||||
|
LED {
|
||||||
|
onColor: "#0f0"
|
||||||
|
text: qsTr("Max. value")
|
||||||
|
}
|
||||||
|
|
||||||
|
LED {
|
||||||
|
onColor: "#00f"
|
||||||
|
text: qsTr("Min. value")
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,29 +60,6 @@ ColumnLayout {
|
|||||||
//
|
//
|
||||||
readonly property var gpsCoordinates: QtPositioning.coordinate(latitude, longitude)
|
readonly property var gpsCoordinates: QtPositioning.coordinate(latitude, longitude)
|
||||||
|
|
||||||
//
|
|
||||||
// Center map when connecting with CanSat
|
|
||||||
//
|
|
||||||
Connections {
|
|
||||||
target: CppQmlBridge
|
|
||||||
|
|
||||||
function onUpdated() {
|
|
||||||
if (oldCoordinates === QtPositioning.coordinate(0,0)) {
|
|
||||||
map.center = gpsCoordinates
|
|
||||||
oldCoordinates = gpsCoordinates
|
|
||||||
}
|
|
||||||
|
|
||||||
gps.latitude = CppQmlBridge.gpsLatitude
|
|
||||||
gps.longitude = CppQmlBridge.gpsLongitude
|
|
||||||
}
|
|
||||||
} Connections {
|
|
||||||
target: CppSerialManager
|
|
||||||
|
|
||||||
function onPortChanged() {
|
|
||||||
oldCoordinates = QtPositioning.coordinate(0,0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Centers the map to Queretaro if the GPS is not working,
|
// Centers the map to Queretaro if the GPS is not working,
|
||||||
// otherwise, centers the map to the CanSat's position
|
// otherwise, centers the map to the CanSat's position
|
||||||
|
@ -106,6 +106,9 @@ ApplicationWindow {
|
|||||||
Timer {
|
Timer {
|
||||||
id: timer
|
id: timer
|
||||||
interval: 500
|
interval: 500
|
||||||
onTriggered: app.visible = true
|
onTriggered: {
|
||||||
|
app.visible = true
|
||||||
|
CppJsonParser.readSettings()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ void Export::closeFile()
|
|||||||
writeValues();
|
writeValues();
|
||||||
|
|
||||||
m_csvFile.close();
|
m_csvFile.close();
|
||||||
|
m_textStream.setDevice(Q_NULLPTR);
|
||||||
|
|
||||||
emit openChanged();
|
emit openChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +230,7 @@ void Export::writeValues()
|
|||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
m_csvFile.setFileName(dir.filePath(fileName));
|
m_csvFile.setFileName(dir.filePath(fileName));
|
||||||
if (!m_csvFile.open(QFile::WriteOnly))
|
if (!m_csvFile.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(Q_NULLPTR, tr("CSV File Error"), tr("Cannot open CSV file for writing!"),
|
QMessageBox::critical(Q_NULLPTR, tr("CSV File Error"), tr("Cannot open CSV file for writing!"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
@ -236,14 +238,17 @@ void Export::writeValues()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add cell titles
|
// Add cell titles & force UTF-8 codec
|
||||||
|
m_textStream.setDevice(&m_csvFile);
|
||||||
|
m_textStream.setCodec("UTF-8");
|
||||||
|
m_textStream.setGenerateByteOrderMark(true);
|
||||||
for (int i = 0; i < titles.count(); ++i)
|
for (int i = 0; i < titles.count(); ++i)
|
||||||
{
|
{
|
||||||
m_csvFile.write(titles.at(i).toUtf8());
|
m_textStream << titles.at(i).toUtf8();
|
||||||
if (i < titles.count() - 1)
|
if (i < titles.count() - 1)
|
||||||
m_csvFile.write(",");
|
m_textStream << ",";
|
||||||
else
|
else
|
||||||
m_csvFile.write("\n");
|
m_textStream << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
@ -253,11 +258,11 @@ void Export::writeValues()
|
|||||||
// Write cell values
|
// Write cell values
|
||||||
for (int i = 0; i < values.count(); ++i)
|
for (int i = 0; i < values.count(); ++i)
|
||||||
{
|
{
|
||||||
m_csvFile.write(values.at(i).toUtf8());
|
m_textStream << values.at(i).toUtf8();
|
||||||
if (i < values.count() - 1)
|
if (i < values.count() - 1)
|
||||||
m_csvFile.write(",");
|
m_textStream << ",";
|
||||||
else
|
else
|
||||||
m_csvFile.write("\n");
|
m_textStream << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove JSON from list
|
// Remove JSON from list
|
||||||
|
@ -47,15 +47,16 @@ private:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void openCsv();
|
void openCsv();
|
||||||
|
void closeFile();
|
||||||
void openCurrentCsv();
|
void openCurrentCsv();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void closeFile();
|
|
||||||
void writeValues();
|
void writeValues();
|
||||||
void updateValues();
|
void updateValues();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QFile m_csvFile;
|
QFile m_csvFile;
|
||||||
|
QTextStream m_textStream;
|
||||||
QList<QPair<QDateTime, QJsonObject>> m_jsonList;
|
QList<QPair<QDateTime, QJsonObject>> m_jsonList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ void JsonParser::loadJsonMap()
|
|||||||
/**
|
/**
|
||||||
* Opens, validates & loads into memory the JSON file in the given @a path.
|
* Opens, validates & loads into memory the JSON file in the given @a path.
|
||||||
*/
|
*/
|
||||||
void JsonParser::loadJsonMap(const QString &path)
|
void JsonParser::loadJsonMap(const QString &path, const bool silent)
|
||||||
{
|
{
|
||||||
// Validate path
|
// Validate path
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
@ -163,23 +163,26 @@ void JsonParser::loadJsonMap(const QString &path)
|
|||||||
if (error.error != QJsonParseError::NoError)
|
if (error.error != QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
m_jsonMap.close();
|
m_jsonMap.close();
|
||||||
|
writeSettings("");
|
||||||
NiceMessageBox(tr("JSON parse error"), error.errorString());
|
NiceMessageBox(tr("JSON parse error"), error.errorString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON contains no errors
|
// JSON contains no errors, load data & save settings
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
writeSettings(path);
|
||||||
m_jsonMapData = QString::fromUtf8(data);
|
m_jsonMapData = QString::fromUtf8(data);
|
||||||
NiceMessageBox(tr("JSON map file loaded successfully!"),
|
if (!silent)
|
||||||
tr("File \"%1\" loaded into memory").arg(jsonMapFilename()));
|
NiceMessageBox(tr("JSON map file loaded successfully!"),
|
||||||
|
tr("File \"%1\" loaded into memory").arg(jsonMapFilename()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open error
|
// Open error
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NiceMessageBox(tr("Cannot read file contents"),
|
writeSettings("");
|
||||||
tr("Failed to read contents of \"%1\", check file permissions").arg(jsonMapFilename()));
|
NiceMessageBox(tr("Cannot read JSON file"), tr("Please check file permissions & location"));
|
||||||
m_jsonMap.close();
|
m_jsonMap.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +207,24 @@ void JsonParser::setOperationMode(const OperationMode mode)
|
|||||||
emit operationModeChanged();
|
emit operationModeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the last saved JSON map file (if any)
|
||||||
|
*/
|
||||||
|
void JsonParser::readSettings()
|
||||||
|
{
|
||||||
|
auto path = m_settings.value("json_map_location", "").toString();
|
||||||
|
if (!path.isEmpty())
|
||||||
|
loadJsonMap(path, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the location of the last valid JSON map file that was opened (if any)
|
||||||
|
*/
|
||||||
|
void JsonParser::writeSettings(const QString &path)
|
||||||
|
{
|
||||||
|
m_settings.setValue("json_map_location", path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to parse the given data as a JSON document according to the selected
|
* Tries to parse the given data as a JSON document according to the selected
|
||||||
* operation mode.
|
* operation mode.
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSettings>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
@ -62,17 +63,22 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadJsonMap();
|
void loadJsonMap();
|
||||||
void loadJsonMap(const QString &path);
|
|
||||||
void setOperationMode(const OperationMode mode);
|
void setOperationMode(const OperationMode mode);
|
||||||
|
void loadJsonMap(const QString &path, const bool silent = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JsonParser();
|
JsonParser();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void readSettings();
|
||||||
|
void writeSettings(const QString &path);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readData(const QByteArray &data);
|
void readData(const QByteArray &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QFile m_jsonMap;
|
QFile m_jsonMap;
|
||||||
|
QSettings m_settings;
|
||||||
QString m_jsonMapData;
|
QString m_jsonMapData;
|
||||||
OperationMode m_opMode;
|
OperationMode m_opMode;
|
||||||
QJsonDocument m_document;
|
QJsonDocument m_document;
|
||||||
|
@ -43,8 +43,5 @@ ModuleManager::ModuleManager()
|
|||||||
*/
|
*/
|
||||||
void ModuleManager::deleteModules()
|
void ModuleManager::deleteModules()
|
||||||
{
|
{
|
||||||
Export::getInstance()->deleteLater();
|
Export::getInstance()->closeFile();
|
||||||
QmlBridge::getInstance()->deleteLater();
|
|
||||||
GraphProvider::getInstance()->deleteLater();
|
|
||||||
SerialManager::getInstance()->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
@ -44,40 +44,40 @@ public:
|
|||||||
QList<Group *> gaugeGroup() const;
|
QList<Group *> gaugeGroup() const;
|
||||||
QList<Group *> accelerometerGroup() const;
|
QList<Group *> accelerometerGroup() const;
|
||||||
|
|
||||||
int barGroupCount() const;
|
Q_INVOKABLE int barGroupCount() const;
|
||||||
int mapGroupCount() const;
|
Q_INVOKABLE int mapGroupCount() const;
|
||||||
int gyroGroupCount() const;
|
Q_INVOKABLE int gyroGroupCount() const;
|
||||||
int tankGroupCount() const;
|
Q_INVOKABLE int tankGroupCount() const;
|
||||||
int gaugeGroupCount() const;
|
Q_INVOKABLE int gaugeGroupCount() const;
|
||||||
int accelerometerGroupCount() const;
|
Q_INVOKABLE int accelerometerGroupCount() const;
|
||||||
|
|
||||||
Group *barGroupAt(const int index);
|
Q_INVOKABLE Group *barGroupAt(const int index);
|
||||||
Group *mapGroupAt(const int index);
|
Q_INVOKABLE Group *mapGroupAt(const int index);
|
||||||
Group *gyroGroupAt(const int index);
|
Q_INVOKABLE Group *gyroGroupAt(const int index);
|
||||||
Group *tankGroupAt(const int index);
|
Q_INVOKABLE Group *tankGroupAt(const int index);
|
||||||
Group *gaugeGroupAt(const int index);
|
Q_INVOKABLE Group *gaugeGroupAt(const int index);
|
||||||
Group *accelerometerGroupAt(const int index);
|
Q_INVOKABLE Group *accelerometerGroupAt(const int index);
|
||||||
|
|
||||||
double gyroX(const int index);
|
Q_INVOKABLE double gyroX(const int index);
|
||||||
double gyroY(const int index);
|
Q_INVOKABLE double gyroY(const int index);
|
||||||
double gyroZ(const int index);
|
Q_INVOKABLE double gyroZ(const int index);
|
||||||
|
|
||||||
double accelerometerX(const int index);
|
Q_INVOKABLE double accelerometerX(const int index);
|
||||||
double accelerometerY(const int index);
|
Q_INVOKABLE double accelerometerY(const int index);
|
||||||
double accelerometerZ(const int index);
|
Q_INVOKABLE double accelerometerZ(const int index);
|
||||||
|
|
||||||
double bar(const int index);
|
Q_INVOKABLE double bar(const int index);
|
||||||
double tank(const int index);
|
Q_INVOKABLE double tank(const int index);
|
||||||
double gauge(const int index);
|
Q_INVOKABLE double gauge(const int index);
|
||||||
double barMin(const int index);
|
Q_INVOKABLE double barMin(const int index);
|
||||||
double barMax(const int index);
|
Q_INVOKABLE double barMax(const int index);
|
||||||
double tankMin(const int index);
|
Q_INVOKABLE double tankMin(const int index);
|
||||||
double tankMax(const int index);
|
Q_INVOKABLE double tankMax(const int index);
|
||||||
double gaugeMin(const int index);
|
Q_INVOKABLE double gaugeMin(const int index);
|
||||||
double gaugeMax(const int index);
|
Q_INVOKABLE double gaugeMax(const int index);
|
||||||
|
|
||||||
double mapLatitude(const int index);
|
Q_INVOKABLE double mapLatitude(const int index);
|
||||||
double mapLongitude(const int index);
|
Q_INVOKABLE double mapLongitude(const int index);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateModels();
|
void updateModels();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user