LibreVNA/Software/PC_Application/Traces/tracecsvexport.cpp
2021-10-21 08:31:31 -03:00

188 lines
5.2 KiB
C++

#include "tracecsvexport.h"
#include "ui_tracecsvexport.h"
#include "csv.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QFileDialog>
using namespace std;
TraceCSVExport::TraceCSVExport(TraceModel &traceModel, QWidget *parent) :
QDialog(parent),
ui(new Ui::TraceCSVExport),
model(traceModel.getTraces())
{
ui->setupUi(this);
ui->listView->setModel(&model);
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(&model, &TraceCSVModel::selectionChanged, ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::setEnabled);
}
TraceCSVExport::~TraceCSVExport()
{
delete ui;
}
void TraceCSVExport::on_buttonBox_accepted()
{
auto traces = model.tracesToExport();
if(traces.size() == 0) {
return;
}
auto filename = QFileDialog::getSaveFileName(nullptr, "Save calibration data", "", "CSV files (*.csv)", nullptr, QFileDialog::DontUseNativeDialog);
if(filename.isEmpty()) {
// aborted selection
return;
}
if(!filename.endsWith(".csv")) {
filename.append(".csv");
}
CSV csv;
// create the first column (X data)
vector<double> X;
QString Xname = Trace::dataTypeToString(traces[0]->outputType());
auto samples = traces[0]->numSamples();
for(unsigned int i=0;i<samples;i++) {
X.push_back(traces[0]->sample(i).x);
}
csv.addColumn(Xname, X);
// add the trace data
for(auto t : traces) {
vector<double> real;
vector<double> imag;
auto samples = t->numSamples();
for(unsigned int i=0;i<samples;i++) {
real.push_back(t->sample(i).y.real());
imag.push_back(t->sample(i).y.imag());
}
// check if this is a real or complex trace
bool allZeros = std::all_of(imag.begin(), imag.end(), [](double i) { return i==0.0; });
if(allZeros) {
// only real values, one column is enough
csv.addColumn(t->name(), real);
} else {
// complex values, need two columns
csv.addColumn(t->name()+"_real", real);
csv.addColumn(t->name()+"_imag", imag);
}
}
csv.toFile(filename);
}
TraceCSVModel::TraceCSVModel(std::vector<Trace *> traces, QObject *parent)
: QAbstractListModel(parent)
{
this->traces = traces;
save.resize(traces.size(), false);
enabled.resize(traces.size(), true);
points = 0;
updateEnabledTraces();
}
int TraceCSVModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return traces.size();
}
QVariant TraceCSVModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid()) {
return QVariant();
}
switch(role) {
case Qt::CheckStateRole:
if(save[index.row()]) {
return Qt::Checked;
} else {
return Qt::Unchecked;
}
case Qt::DisplayRole:
return traces[index.row()]->name();
default:
return QVariant();
}
}
bool TraceCSVModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(!index.isValid()) {
return false;
}
if(role==Qt::CheckStateRole) {
save[index.row()] = !save[index.row()];
updateEnabledTraces();
return true;
} else {
return QAbstractItemModel::setData(index, value, role);
}
}
Qt::ItemFlags TraceCSVModel::flags(const QModelIndex &index) const
{
unsigned int flags = Qt::ItemIsUserCheckable;
if(index.isValid()) {
if(enabled[index.row()]) {
flags |= Qt::ItemIsEnabled;
}
}
return (Qt::ItemFlags) flags;
}
std::vector<Trace *> TraceCSVModel::tracesToExport()
{
vector<Trace*> ret;
for(unsigned int i=0;i<traces.size();i++) {
if(save[i]) {
ret.push_back(traces[i]);
}
}
return ret;
}
void TraceCSVModel::updateEnabledTraces()
{
beginResetModel();
// find first selected trace and use its settings
points = 0;
type = Trace::DataType::Invalid;
for(unsigned int i=0;i<traces.size();i++) {
if(save[i]) {
points = traces[i]->numSamples();
minX = traces[i]->minX();
maxX = traces[i]->maxX();
type = traces[i]->outputType();
}
}
// second pass: compare to the settings and only enable identical traces
for(unsigned int i=0;i<traces.size();i++) {
auto enableTrace = true;
if(traces[i]->numSamples() == 0 || traces[i]->outputType() == Trace::DataType::Invalid) {
// trace has no valid data, unable to export
enableTrace = false;
}
if(points > 0 && type != Trace::DataType::Invalid) {
// check if this trace matches the already selected one
if((traces[i]->numSamples() != points)
|| (traces[i]->minX() != minX)
|| (traces[i]->maxX() != maxX)
|| (traces[i]->outputType() != type)) {
// different settings, not possible to export in this combination
enableTrace = false;
}
}
enabled[i] = enableTrace;
if(!enableTrace) {
save[i] = false;
}
}
endResetModel();
emit selectionChanged(points > 0);
}