# HG changeset patch # User Chris Cannam # Date 1586177744 -3600 # Node ID 804dd0c06f0e442ef931c89a9514beacab6caf47 # Parent 7c92c644db2093ae82547ad2daf221ce0753055c# Parent 735b0ccd3f4ae758633950d7f53e897dd93156ed Merge from branch sensible-delimited-data-strings diff -r 7c92c644db20 -r 804dd0c06f0e base/Event.h --- a/base/Event.h Fri Apr 03 12:12:02 2020 +0100 +++ b/base/Event.h Mon Apr 06 13:55:44 2020 +0100 @@ -366,9 +366,9 @@ return n; } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions opts, - ExportNameOptions nameOpts) const { + QVector + getStringExportHeaders(DataExportOptions opts, + ExportNameOptions nameOpts) const { QStringList list; @@ -400,13 +400,18 @@ } list << "label"; + + QVector sv; + for (QString s: list) { + sv.push_back(s.toUpper()); + } + return sv; + } + + QVector + toStringExportRow(DataExportOptions opts, + sv_samplerate_t sampleRate) const { - return list.join(delimiter).toUpper(); - } - - QString toDelimitedDataString(QString delimiter, - DataExportOptions opts, - sv_samplerate_t sampleRate) const { QStringList list; if (opts & DataExportWriteTimeInFrames) { @@ -441,8 +446,8 @@ // facility for the user to customise it if (m_uri != "") list << m_uri; if (m_label != "") list << m_label; - - return list.join(delimiter); + + return list.toVector(); } uint hash(uint seed = 0) const { diff -r 7c92c644db20 -r 804dd0c06f0e base/EventSeries.cpp --- a/base/EventSeries.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/base/EventSeries.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -16,6 +16,9 @@ #include +using std::vector; +using std::string; + EventSeries::EventSeries(const EventSeries &other) : EventSeries(other, QMutexLocker(&other.m_mutex)) { @@ -597,32 +600,28 @@ out << indent << "\n"; } -QString -EventSeries::getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions opts, - Event::ExportNameOptions nopts) const +QVector +EventSeries::getStringExportHeaders(DataExportOptions opts, + Event::ExportNameOptions nopts) const { if (m_events.empty()) { - return QString(); + return {}; } else { - return m_events.begin()->getDelimitedDataHeaderLine(delimiter, - opts, - nopts); + return m_events.begin()->getStringExportHeaders(opts, nopts); } } -QString -EventSeries::toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration, - sv_samplerate_t sampleRate, - sv_frame_t resolution, - Event fillEvent) const +QVector> +EventSeries::toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration, + sv_samplerate_t sampleRate, + sv_frame_t resolution, + Event fillEvent) const { QMutexLocker locker(&m_mutex); - QString s; + QVector> rows; const sv_frame_t end = startFrame + duration; @@ -632,10 +631,7 @@ if (!(options & DataExportFillGaps)) { while (pitr != m_events.end() && pitr->getFrame() < end) { - s += pitr->toDelimitedDataString(delimiter, - options, - sampleRate); - s += "\n"; + rows.push_back(pitr->toStringExportRow(options, sampleRate)); ++pitr; } @@ -659,22 +655,19 @@ // distance) or a default fill point while (f < end) { if (pitr != m_events.end() && pitr->getFrame() <= f) { - s += pitr->toDelimitedDataString - (delimiter, - options & ~DataExportFillGaps, - sampleRate); + rows.push_back(pitr->toStringExportRow + (options & ~DataExportFillGaps, + sampleRate)); ++pitr; } else { - s += fillEvent.withFrame(f).toDelimitedDataString - (delimiter, - options & ~DataExportFillGaps, - sampleRate); + rows.push_back(fillEvent.withFrame(f).toStringExportRow + (options & ~DataExportFillGaps, + sampleRate)); } - s += "\n"; f += resolution; } } - return s; + return rows; } diff -r 7c92c644db20 -r 804dd0c06f0e base/EventSeries.h --- a/base/EventSeries.h Fri Apr 03 12:12:02 2020 +0100 +++ b/base/EventSeries.h Mon Apr 06 13:55:44 2020 +0100 @@ -19,6 +19,8 @@ #include "XmlExportable.h" #include +#include +#include #include #include @@ -221,24 +223,24 @@ Event::ExportNameOptions) const; /** - * Emit a label for each column that would be written by - * toDelimitedDataString, separated by the given delimiter. + * Return a label for each column that would be written by + * toStringExportRows. */ - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options, - Event::ExportNameOptions) const; + QVector + getStringExportHeaders(DataExportOptions options, + Event::ExportNameOptions) const; /** - * Emit events starting within the given range to a delimited - * (e.g. comma-separated) data format. + * Emit events starting within the given range as string rows + * ready for conversion to an e.g. comma-separated data format. */ - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration, - sv_samplerate_t sampleRate, - sv_frame_t resolution, - Event fillEvent) const; + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration, + sv_samplerate_t sampleRate, + sv_frame_t resolution, + Event fillEvent) const; private: mutable QMutex m_mutex; diff -r 7c92c644db20 -r 804dd0c06f0e base/StringBits.cpp --- a/base/StringBits.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/base/StringBits.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -151,3 +151,20 @@ } } +QString +StringBits::joinDelimited(QVector row, QString delimiter) +{ + QString s; + for (auto col: row) { + if (s != "") { + s += delimiter; + } + if (col.contains(delimiter)) { + col.replace("\"", "\"\""); + col = "\"" + col + "\""; + } + s += col; + } + return s; +} + diff -r 7c92c644db20 -r 804dd0c06f0e base/StringBits.h --- a/base/StringBits.h Fri Apr 03 12:12:02 2020 +0100 +++ b/base/StringBits.h Mon Apr 06 13:55:44 2020 +0100 @@ -55,6 +55,16 @@ * analogous to the behaviour of splitQuoted). */ static QStringList split(QString s, QChar separator, bool quoted); + + /** + * Join a vector of strings into a single string, with the + * delimiter as the joining string. If a string contains the + * delimiter already, quote it with double-quotes, replacing any + * existing double-quotes within it by a pair of double-quotes, as + * specified in RFC 4180 Common Format and MIME Type for + * Comma-Separated Values (CSV) Files. + */ + static QString joinDelimited(QVector row, QString delimiter); }; #endif diff -r 7c92c644db20 -r 804dd0c06f0e data/fileio/CSVFileWriter.cpp --- a/data/fileio/CSVFileWriter.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/data/fileio/CSVFileWriter.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -86,7 +86,9 @@ QTextStream out(&file); if (m_options & DataExportIncludeHeader) { - out << m_model->getDelimitedDataHeaderLine(m_delimiter, m_options) + out << StringBits::joinDelimited + (m_model->getStringExportHeaders(m_options), + m_delimiter) << endl; } diff -r 7c92c644db20 -r 804dd0c06f0e data/fileio/CSVStreamWriter.h --- a/data/fileio/CSVStreamWriter.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/fileio/CSVStreamWriter.h Mon Apr 06 13:55:44 2020 +0100 @@ -20,7 +20,9 @@ #include "base/Selection.h" #include "base/ProgressReporter.h" #include "base/DataExportOptions.h" +#include "base/StringBits.h" #include "data/model/Model.h" + #include #include #include @@ -68,20 +70,21 @@ const auto start = readPtr; const auto end = std::min(start + blockSize, endFrame); - const auto data = model.toDelimitedDataString( - delimiter, + const auto data = model.toStringExportRows( options, start, end - start - ).trimmed(); + ); - if ( data != "" ) { - if (started) { - oss << "\n"; - } else { - started = true; + if (!data.empty()) { + for (const auto &row: data) { + if (started) { + oss << "\n"; + } else { + started = true; + } + oss << StringBits::joinDelimited(row, delimiter); } - oss << data; } nFramesWritten += end - start; @@ -120,7 +123,7 @@ }; MultiSelection regions; regions.addSelection(all); - return CSVStreamWriter::writeInChunks( + return writeInChunks( oss, model, regions, @@ -141,7 +144,7 @@ const sv_frame_t blockSize = 16384) { const Selection empty; - return CSVStreamWriter::writeInChunks( + return writeInChunks( oss, model, empty, diff -r 7c92c644db20 -r 804dd0c06f0e data/fileio/test/CSVStreamWriterTest.h --- a/data/fileio/test/CSVStreamWriterTest.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/fileio/test/CSVStreamWriterTest.h Mon Apr 06 13:55:44 2020 +0100 @@ -94,6 +94,7 @@ std::ostringstream oss; const auto result = CSVStreamWriter::writeInChunks(oss, mwm); + QVERIFY( oss.str() == getExpectedString() ); QVERIFY( result ); } @@ -303,9 +304,12 @@ // qDebug("Create Expected Output\n"); // NB. removed end line break - const auto expectedOutput = - notes.toDelimitedDataString(",", {}, 0, notes.getEndFrame()) - .trimmed(); + QString expectedOutput; + auto rows = notes.toStringExportRows({}, 0, notes.getEndFrame()); + for (auto row: rows) { + expectedOutput += StringBits::joinDelimited(row, ",") + "\n"; + } + expectedOutput = expectedOutput.trimmed(); StubReporter reporter { []() -> bool { return false; } }; std::ostringstream oss; @@ -326,6 +330,70 @@ QVERIFY( oss.str() != std::string() ); QVERIFY( oss.str() == expectedOutput.toStdString() ); } + + void writeWithQuotingRequired() + { + QString commaLabel = + "This label contains punctuation, specifically, commas"; + QString quoteSpaceLabel = + "This label contains spaces and \"double quotes\""; + + NoteModel notes(8, 4); + notes.add({ 0, 64, 4, 1.f, commaLabel }); + notes.add({ 16, 64, 6, 1.f, quoteSpaceLabel }); + + QString expectedWithCommaSeparator = + QString("0.000000000,64,0.500000000,1,\"") + + commaLabel + + QString("\"\n") + + QString("2.000000000,64,0.750000000,1,") + + quoteSpaceLabel; + + QString expectedWithSpaceSeparator = + QString("0.000000000 64 0.500000000 1 \"") + + commaLabel + + QString("\"\n") + + QString("2.000000000 64 0.750000000 1 \"") + + QString("This label contains spaces and \"\"double quotes\"\"") + + QString("\""); + + StubReporter reporter { []() -> bool { return false; } }; + std::ostringstream oss; + auto wroteSparseModel = CSVStreamWriter::writeInChunks( + oss, + notes, + &reporter, + ",", + DataExportDefaults, + 2 + ); + + QVERIFY( wroteSparseModel == true ); + QVERIFY( oss.str() != std::string() ); + + cerr << oss.str() << endl; + cerr << expectedWithCommaSeparator << endl; + + QVERIFY( oss.str() == expectedWithCommaSeparator.toStdString() ); + + std::ostringstream oss2; + wroteSparseModel = CSVStreamWriter::writeInChunks( + oss2, + notes, + &reporter, + " ", + DataExportDefaults, + 2 + ); + + QVERIFY( wroteSparseModel == true ); + QVERIFY( oss2.str() != std::string() ); + + cerr << oss2.str() << endl; + cerr << expectedWithSpaceSeparator << endl; + + QVERIFY( oss2.str() == expectedWithSpaceSeparator.toStdString() ); + } }; #endif diff -r 7c92c644db20 -r 804dd0c06f0e data/model/AlignmentModel.h --- a/data/model/AlignmentModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/AlignmentModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -77,13 +77,14 @@ QString indent = "", QString extraAttributes = "") const override; - QString getDelimitedDataHeaderLine(QString, DataExportOptions) const override { - return ""; + QVector + getStringExportHeaders(DataExportOptions) const override { + return {}; } - - QString toDelimitedDataString(QString, DataExportOptions, - sv_frame_t, sv_frame_t) const override { - return ""; + + QVector> + toStringExportRows(DataExportOptions, sv_frame_t, sv_frame_t) const override { + return {}; } signals: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/BasicCompressedDenseThreeDimensionalModel.cpp --- a/data/model/BasicCompressedDenseThreeDimensionalModel.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/BasicCompressedDenseThreeDimensionalModel.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -498,37 +498,40 @@ return m_completion; } -QString -BasicCompressedDenseThreeDimensionalModel::getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions) const +QVector +BasicCompressedDenseThreeDimensionalModel::getStringExportHeaders(DataExportOptions) + const { - QStringList list; + QVector sv; for (int i = 0; i < m_yBinCount; ++i) { - list << QString("Bin%1").arg(i+1); + sv.push_back(QString("Bin%1").arg(i+1)); } - return list.join(delimiter); + return sv; } - -QString -BasicCompressedDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter, - DataExportOptions, - sv_frame_t startFrame, - sv_frame_t duration) const + +QVector> +BasicCompressedDenseThreeDimensionalModel::toStringExportRows(DataExportOptions, + sv_frame_t startFrame, + sv_frame_t duration) + const { QReadLocker locker(&m_lock); - QString s; + + QVector> rows; + for (int i = 0; in_range_for(m_data, i); ++i) { Column c = getColumn(i); sv_frame_t fr = m_startFrame + i * m_resolution; if (fr >= startFrame && fr < startFrame + duration) { - QStringList list; + QVector row; for (int j = 0; in_range_for(c, j); ++j) { - list << QString("%1").arg(c.at(j)); + row << QString("%1").arg(c.at(j)); } - s += list.join(delimiter) + "\n"; + rows.push_back(row); } } - return s; + + return rows; } void diff -r 7c92c644db20 -r 804dd0c06f0e data/model/BasicCompressedDenseThreeDimensionalModel.h --- a/data/model/BasicCompressedDenseThreeDimensionalModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/BasicCompressedDenseThreeDimensionalModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -181,13 +181,13 @@ QString getTypeName() const override { return tr("Editable Dense 3-D"); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions opts) const override; + QVector + getStringExportHeaders(DataExportOptions options) const override; - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override; + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override; void toXml(QTextStream &out, QString indent = "", diff -r 7c92c644db20 -r 804dd0c06f0e data/model/BoxModel.h --- a/data/model/BoxModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/BoxModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -348,8 +348,9 @@ m_events.toXml(out, indent, QString("dimensions=\"2\""), options); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions opts) const override { + QVector + getStringExportHeaders(DataExportOptions opts) const override { + QStringList list; // These are considered API rather than human-readable text - @@ -363,23 +364,27 @@ list << "extent start" << "extent end" << "label"; - return list.join(delimiter).toUpper(); + QVector sv; + for (QString s: list) { + sv.push_back(s.toUpper()); + } + return sv; } - QString toDelimitedDataString(QString delimiter, - DataExportOptions opts, - sv_frame_t startFrame, - sv_frame_t duration) const override { + QVector> + toStringExportRows(DataExportOptions opts, + sv_frame_t startFrame, + sv_frame_t duration) const override { // We need a custom format here EventVector ee = m_events.getEventsSpanning(startFrame, duration); - QString s; + QVector> rows; for (auto e: ee) { - QStringList list; + QVector list; if (opts & DataExportWriteTimeInFrames) { @@ -405,10 +410,10 @@ list << e.getLabel(); } - s += list.join(delimiter) + "\n"; + rows.push_back(list); } - return s; + return rows; } protected: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/Dense3DModelPeakCache.h --- a/data/model/Dense3DModelPeakCache.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/Dense3DModelPeakCache.h Mon Apr 06 13:55:44 2020 +0100 @@ -119,13 +119,14 @@ return source ? source->getCompletion() : 100; } - QString getDelimitedDataHeaderLine(QString, DataExportOptions) const override { - return ""; + QVector + getStringExportHeaders(DataExportOptions) const override { + return {}; } - - QString toDelimitedDataString(QString, DataExportOptions, - sv_frame_t, sv_frame_t) const override { - return ""; + + QVector> + toStringExportRows(DataExportOptions, sv_frame_t, sv_frame_t) const override { + return {}; } protected slots: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/DenseTimeValueModel.cpp --- a/data/model/DenseTimeValueModel.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/DenseTimeValueModel.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -17,41 +17,42 @@ #include -QString -DenseTimeValueModel::getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions) const +using namespace std; + +QVector +DenseTimeValueModel::getStringExportHeaders(DataExportOptions) const { int ch = getChannelCount(); - QStringList list; + QVector sv; for (int i = 0; i < ch; ++i) { - list << QString("Channel%1").arg(i+1); + sv.push_back(QString("Channel%1").arg(i+1)); } - return list.join(delimiter); + return sv; } -QString -DenseTimeValueModel::toDelimitedDataString(QString delimiter, - DataExportOptions, - sv_frame_t startFrame, - sv_frame_t duration) const +QVector> +DenseTimeValueModel::toStringExportRows(DataExportOptions, + sv_frame_t startFrame, + sv_frame_t duration) const { int ch = getChannelCount(); - if (duration <= 0) return ""; + if (duration <= 0) return {}; auto data = getMultiChannelData(0, ch - 1, startFrame, duration); - if (data.empty() || data[0].empty()) return ""; + if (data.empty() || data[0].empty()) return {}; - QStringList list; + QVector> rows; + for (sv_frame_t i = 0; in_range_for(data[0], i); ++i) { - QStringList parts; - parts << QString("%1").arg(startFrame + i); + QVector row; + row.push_back(QString("%1").arg(startFrame + i)); for (int c = 0; in_range_for(data, c); ++c) { - parts << QString("%1").arg(data[c][i]); + row.push_back(QString("%1").arg(data[c][i])); } - list << parts.join(delimiter); + rows.push_back(row); } - return list.join("\n"); + return rows; } diff -r 7c92c644db20 -r 804dd0c06f0e data/model/DenseTimeValueModel.h --- a/data/model/DenseTimeValueModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/DenseTimeValueModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -82,13 +82,13 @@ bool canPlay() const override { return true; } QString getDefaultPlayClipId() const override { return ""; } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override; - - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override; + QVector + getStringExportHeaders(DataExportOptions options) const override; + + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override; QString getTypeName() const override { return tr("Dense Time-Value"); } }; diff -r 7c92c644db20 -r 804dd0c06f0e data/model/EditableDenseThreeDimensionalModel.cpp --- a/data/model/EditableDenseThreeDimensionalModel.cpp Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/EditableDenseThreeDimensionalModel.cpp Mon Apr 06 13:55:44 2020 +0100 @@ -351,36 +351,38 @@ return m_completion; } -QString -EditableDenseThreeDimensionalModel::getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions) const +QVector +EditableDenseThreeDimensionalModel::getStringExportHeaders(DataExportOptions) + const { - QStringList list; + QVector sv; for (int i = 0; i < m_yBinCount; ++i) { - list << QString("Bin%1").arg(i+1); + sv.push_back(QString("Bin%1").arg(i+1)); } - return list.join(delimiter); + return sv; } -QString -EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter, - DataExportOptions, - sv_frame_t startFrame, - sv_frame_t duration) const +QVector> +EditableDenseThreeDimensionalModel::toStringExportRows(DataExportOptions, + sv_frame_t startFrame, + sv_frame_t duration) + const { QMutexLocker locker(&m_mutex); - QString s; + + QVector> rows; + for (int i = 0; in_range_for(m_data, i); ++i) { sv_frame_t fr = m_startFrame + i * m_resolution; if (fr >= startFrame && fr < startFrame + duration) { - QStringList list; + QVector row; for (int j = 0; in_range_for(m_data.at(i), j); ++j) { - list << QString("%1").arg(m_data.at(i).at(j)); + row.push_back(QString("%1").arg(m_data.at(i).at(j))); } - s += list.join(delimiter) + "\n"; + rows.push_back(row); } } - return s; + return rows; } void diff -r 7c92c644db20 -r 804dd0c06f0e data/model/EditableDenseThreeDimensionalModel.h --- a/data/model/EditableDenseThreeDimensionalModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/EditableDenseThreeDimensionalModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -172,13 +172,13 @@ QString getTypeName() const override { return tr("Editable Dense 3-D"); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions opts) const override; + QVector + getStringExportHeaders(DataExportOptions options) const override; - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override; + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override; void toXml(QTextStream &out, QString indent = "", diff -r 7c92c644db20 -r 804dd0c06f0e data/model/FFTModel.h --- a/data/model/FFTModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/FFTModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -99,12 +99,14 @@ float getBinValue(int n) const override; QString getBinName(int n) const override; - QString getDelimitedDataHeaderLine(QString, DataExportOptions) const override { - return ""; + QVector + getStringExportHeaders(DataExportOptions) const override { + return {}; } - QString toDelimitedDataString(QString, DataExportOptions, - sv_frame_t, sv_frame_t) const override { - return ""; + + QVector> + toStringExportRows(DataExportOptions, sv_frame_t, sv_frame_t) const override { + return {}; } // FFTModel methods: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/ImageModel.h --- a/data/model/ImageModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/ImageModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -275,27 +275,23 @@ m_events.toXml(out, indent, QString("dimensions=\"1\""), options); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { + QVector + getStringExportHeaders(DataExportOptions options) const override { Event::ExportNameOptions nameOpts; nameOpts.uriAttributeName = "image"; - - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - nameOpts); + return m_events.getStringExportHeaders(options, nameOpts); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString(delimiter, - options, - startFrame, - duration, - m_sampleRate, - m_resolution, - Event().withValue(0.f)); + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows(options, + startFrame, + duration, + m_sampleRate, + m_resolution, + Event().withValue(0.f)); } protected: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/Model.h --- a/data/model/Model.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/Model.h Mon Apr 06 13:55:44 2020 +0100 @@ -275,20 +275,20 @@ QString extraAttributes = "") const override; /** - * Emit a label for each column that would be written by - * toDelimitedDataString, separated by the given delimiter. + * Return a label for each column that would be written by + * toStringExportRows. */ - virtual QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const = 0; + virtual QVector + getStringExportHeaders(DataExportOptions options) const = 0; /** - * Emit the contents of the model within the given range to a - * delimited (e.g. comma-separated) data format. + * Emit events starting within the given range as string rows + * ready for conversion to an e.g. comma-separated data format. */ - virtual QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const = 0; + virtual QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const = 0; signals: /** diff -r 7c92c644db20 -r 804dd0c06f0e data/model/NoteModel.h --- a/data/model/NoteModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/NoteModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -408,20 +408,17 @@ m_events.toXml(out, indent, QString("dimensions=\"3\"")); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - Event::ExportNameOptions()); + QVector + getStringExportHeaders(DataExportOptions options) const override { + return m_events.getStringExportHeaders(options, {}); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString - (delimiter, - options, + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows + (options, startFrame, duration, m_sampleRate, diff -r 7c92c644db20 -r 804dd0c06f0e data/model/RegionModel.h --- a/data/model/RegionModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/RegionModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -340,20 +340,17 @@ m_events.toXml(out, indent, QString("dimensions=\"3\"")); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - Event::ExportNameOptions()); + QVector + getStringExportHeaders(DataExportOptions options) const override { + return m_events.getStringExportHeaders(options, {}); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString - (delimiter, - options, + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows + (options, startFrame, duration, m_sampleRate, diff -r 7c92c644db20 -r 804dd0c06f0e data/model/SparseOneDimensionalModel.h --- a/data/model/SparseOneDimensionalModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/SparseOneDimensionalModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -308,24 +308,21 @@ m_events.toXml(out, indent, QString("dimensions=\"1\"")); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - Event::ExportNameOptions()); + QVector + getStringExportHeaders(DataExportOptions options) const override { + return m_events.getStringExportHeaders(options, {}); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString(delimiter, - options, - startFrame, - duration, - m_sampleRate, - m_resolution, - Event()); + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows(options, + startFrame, + duration, + m_sampleRate, + m_resolution, + {}); } protected: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/SparseTimeValueModel.h --- a/data/model/SparseTimeValueModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/SparseTimeValueModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -347,24 +347,21 @@ m_events.toXml(out, indent, QString("dimensions=\"2\"")); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - Event::ExportNameOptions()); + QVector + getStringExportHeaders(DataExportOptions options) const override { + return m_events.getStringExportHeaders(options, {}); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString(delimiter, - options, - startFrame, - duration, - m_sampleRate, - m_resolution, - Event().withValue(0.f)); + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows(options, + startFrame, + duration, + m_sampleRate, + m_resolution, + Event().withValue(0.f)); } protected: diff -r 7c92c644db20 -r 804dd0c06f0e data/model/TextModel.h --- a/data/model/TextModel.h Fri Apr 03 12:12:02 2020 +0100 +++ b/data/model/TextModel.h Mon Apr 06 13:55:44 2020 +0100 @@ -278,26 +278,23 @@ m_events.toXml(out, indent, QString("dimensions=\"2\""), options); } - QString getDelimitedDataHeaderLine(QString delimiter, - DataExportOptions options) const override { + QVector + getStringExportHeaders(DataExportOptions options) const override { Event::ExportNameOptions nameOpts; nameOpts.valueAttributeName = "height"; - return m_events.getDelimitedDataHeaderLine(delimiter, - options, - nameOpts); + return m_events.getStringExportHeaders(options, nameOpts); } - QString toDelimitedDataString(QString delimiter, - DataExportOptions options, - sv_frame_t startFrame, - sv_frame_t duration) const override { - return m_events.toDelimitedDataString(delimiter, - options, - startFrame, - duration, - m_sampleRate, - m_resolution, - Event().withValue(0.f)); + QVector> + toStringExportRows(DataExportOptions options, + sv_frame_t startFrame, + sv_frame_t duration) const override { + return m_events.toStringExportRows(options, + startFrame, + duration, + m_sampleRate, + m_resolution, + Event().withValue(0.f)); } protected: