Chris@378: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@378: Chris@378: /* Chris@378: Sonic Visualiser Chris@378: An audio file viewer and annotation editor. Chris@378: Centre for Digital Music, Queen Mary, University of London. Chris@1319: This file copyright 2006-2018 Chris Cannam and QMUL. Chris@378: Chris@378: This program is free software; you can redistribute it and/or Chris@378: modify it under the terms of the GNU General Public License as Chris@378: published by the Free Software Foundation; either version 2 of the Chris@378: License, or (at your option) any later version. See the file Chris@378: COPYING included with this distribution for more information. Chris@378: */ Chris@378: Chris@378: #include "CSVFormatDialog.h" Chris@378: Chris@561: #include "layer/LayerFactory.h" Chris@561: Chris@674: #include "TextAbbrev.h" Chris@674: Chris@378: #include Chris@378: #include Chris@378: #include Chris@378: #include Chris@378: #include Chris@378: #include Chris@378: #include Chris@378: #include Chris@512: #include Chris@378: Chris@560: #include Chris@913: #include Chris@378: Chris@682: #include "base/Debug.h" Chris@682: Chris@1413: CSVFormatDialog::CSVFormatDialog(QWidget *parent, Chris@1413: CSVFormat format, Chris@581: int maxDisplayCols) : Chris@378: QDialog(parent), Chris@1413: m_csvFilePath(""), Chris@1413: m_referenceSampleRate(0), Chris@581: m_format(format), Chris@581: m_maxDisplayCols(maxDisplayCols), Chris@581: m_fuzzyColumn(-1) Chris@378: { Chris@1413: init(); Chris@1413: } Chris@1413: Chris@1413: CSVFormatDialog::CSVFormatDialog(QWidget *parent, Chris@1413: QString csvFilePath, Chris@1413: sv_samplerate_t referenceSampleRate, Chris@1413: int maxDisplayCols) : Chris@1413: QDialog(parent), Chris@1413: m_csvFilePath(csvFilePath), Chris@1413: m_referenceSampleRate(referenceSampleRate), Chris@1413: m_maxDisplayCols(maxDisplayCols), Chris@1413: m_fuzzyColumn(-1) Chris@1413: { Chris@1413: m_format = CSVFormat(csvFilePath); Chris@1413: m_format.setSampleRate(referenceSampleRate); Chris@1413: init(); Chris@1413: } Chris@1413: Chris@1413: CSVFormatDialog::~CSVFormatDialog() Chris@1413: { Chris@1413: } Chris@1413: Chris@1413: static int sampleRates[] = { Chris@1413: 8000, 11025, 12000, 22050, 24000, 32000, Chris@1413: 44100, 48000, 88200, 96000, 176400, 192000 Chris@1413: }; Chris@1413: Chris@1413: void Chris@1413: CSVFormatDialog::init() Chris@1413: { Chris@378: setModal(true); Chris@378: setWindowTitle(tr("Select Data Format")); Chris@1413: Chris@378: QGridLayout *layout = new QGridLayout; Chris@378: Chris@560: int row = 0; Chris@378: Chris@1318: layout->addWidget Chris@1318: (new QLabel(tr("Please select the correct data format for this file.")), Chris@1318: row++, 0, 1, 4); Chris@560: Chris@1413: m_exampleFrame = nullptr; Chris@1413: m_exampleFrameRow = row++; Chris@1413: Chris@1413: std::set plausible = m_format.getPlausibleSeparators(); Chris@1413: SVDEBUG << "Have " << plausible.size() << " plausible separator(s)" << endl; Chris@1413: Chris@1413: if (m_csvFilePath != "" && plausible.size() > 1) { Chris@1413: // can only update when separator changed if we still have a Chris@1413: // file to refer to Chris@1413: layout->addWidget(new QLabel(tr("Column separator:")), row, 0); Chris@1413: m_separatorCombo = new QComboBox; Chris@1413: for (QChar c: plausible) { Chris@1413: m_separatorCombo->addItem(QString(c)); Chris@1413: if (c == m_format.getSeparator()) { Chris@1413: m_separatorCombo->setCurrentIndex(m_separatorCombo->count()-1); Chris@1413: } Chris@1413: } Chris@1413: m_separatorCombo->setEditable(false); Chris@1413: Chris@1413: layout->addWidget(m_separatorCombo, row++, 1); Chris@1413: connect(m_separatorCombo, SIGNAL(activated(QString)), Chris@1413: this, SLOT(separatorChanged(QString))); Chris@1413: } Chris@1413: Chris@1413: layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0); Chris@1413: Chris@1413: m_timingTypeCombo = new QComboBox; Chris@1413: Chris@1413: m_timingLabels = { Chris@1413: { TimingExplicitSeconds, tr("Explicitly, in seconds") }, Chris@1413: { TimingExplicitMsec, tr("Explicitly, in milliseconds") }, Chris@1413: { TimingExplicitSamples, tr("Explicitly, in audio sample frames") }, Chris@1413: { TimingImplicit, tr("Implicitly: rows are equally spaced in time") } Chris@1413: }; Chris@1413: Chris@1413: for (auto &l: m_timingLabels) { Chris@1413: m_timingTypeCombo->addItem(l.second); Chris@1413: } Chris@1413: Chris@1413: layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2); Chris@1413: Chris@1413: connect(m_timingTypeCombo, SIGNAL(activated(int)), Chris@1413: this, SLOT(timingTypeChanged(int))); Chris@1413: Chris@1413: m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):")); Chris@1413: layout->addWidget(m_sampleRateLabel, row, 0); Chris@1413: Chris@1413: m_sampleRateCombo = new QComboBox; Chris@1413: for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) { Chris@1413: m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i])); Chris@1413: } Chris@1413: m_sampleRateCombo->setEditable(true); Chris@1413: Chris@1413: layout->addWidget(m_sampleRateCombo, row++, 1); Chris@1413: connect(m_sampleRateCombo, SIGNAL(activated(QString)), Chris@1413: this, SLOT(sampleRateChanged(QString))); Chris@1413: connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)), Chris@1413: this, SLOT(sampleRateChanged(QString))); Chris@1413: Chris@1413: m_windowSizeLabel = new QLabel(tr("Frame increment between rows:")); Chris@1413: layout->addWidget(m_windowSizeLabel, row, 0); Chris@1413: Chris@1413: m_windowSizeCombo = new QComboBox; Chris@1413: for (int i = 0; i <= 16; ++i) { Chris@1413: int value = 1 << i; Chris@1413: m_windowSizeCombo->addItem(QString("%1").arg(value)); Chris@1413: } Chris@1413: m_windowSizeCombo->setEditable(true); Chris@1413: Chris@1413: layout->addWidget(m_windowSizeCombo, row++, 1); Chris@1413: connect(m_windowSizeCombo, SIGNAL(activated(QString)), Chris@1413: this, SLOT(windowSizeChanged(QString))); Chris@1413: connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)), Chris@1413: this, SLOT(windowSizeChanged(QString))); Chris@1413: Chris@1413: m_modelLabel = new QLabel; Chris@1413: QFont f(m_modelLabel->font()); Chris@1413: f.setItalic(true); Chris@1413: m_modelLabel->setFont(f); Chris@1413: layout->addWidget(m_modelLabel, row++, 0, 1, 4); Chris@1413: Chris@1413: QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok | Chris@1413: QDialogButtonBox::Cancel); Chris@1413: layout->addWidget(bb, row++, 0, 1, 4); Chris@1413: connect(bb, SIGNAL(accepted()), this, SLOT(accept())); Chris@1413: connect(bb, SIGNAL(rejected()), this, SLOT(reject())); Chris@1413: Chris@1413: setLayout(layout); Chris@1413: Chris@1413: repopulate(); Chris@1413: } Chris@1413: Chris@1413: void Chris@1413: CSVFormatDialog::repopulate() Chris@1413: { Chris@1413: SVCERR << "CSVFormatDialog::repopulate()" << endl; Chris@1413: Chris@1413: QGridLayout *layout = qobject_cast(this->layout()); Chris@1413: Chris@560: QFrame *exampleFrame = new QFrame; Chris@560: exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); Chris@560: exampleFrame->setLineWidth(2); Chris@560: QGridLayout *exampleLayout = new QGridLayout; Chris@561: exampleLayout->setSpacing(4); Chris@560: exampleFrame->setLayout(exampleLayout); Chris@560: Chris@560: QPalette palette = exampleFrame->palette(); Chris@560: palette.setColor(QPalette::Window, palette.color(QPalette::Base)); Chris@560: exampleFrame->setPalette(palette); Chris@560: Chris@560: QFont fp; Chris@908: fp.setPointSize(int(floor(fp.pointSize() * 0.9))); Chris@560: Chris@1413: int columns = m_format.getColumnCount(); Chris@560: QList example = m_format.getExample(); Chris@560: Chris@1413: m_columnPurposeCombos.clear(); Chris@1413: Chris@560: for (int i = 0; i < columns; ++i) { Chris@581: Chris@560: QComboBox *cpc = new QComboBox; Chris@560: m_columnPurposeCombos.push_back(cpc); Chris@560: exampleLayout->addWidget(cpc, 0, i); Chris@581: connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int))); Chris@1318: Chris@581: if (i == m_maxDisplayCols && columns > i + 2) { Chris@581: m_fuzzyColumn = i; Chris@1318: Chris@1319: cpc->addItem(tr("")); Chris@1319: cpc->addItem(tr("Values")); Chris@1319: cpc->setCurrentIndex Chris@1319: (m_format.getColumnPurpose(i-1) == Chris@1319: CSVFormat::ColumnUnknown ? 0 : 1); Chris@1319: Chris@1318: exampleLayout->addWidget Chris@1318: (new QLabel(tr("(%1 more)").arg(columns - i)), 1, i); Chris@581: break; Chris@581: } Chris@560: Chris@1319: // NB must be in the same order as the CSVFormat::ColumnPurpose enum Chris@1319: cpc->addItem(tr("")); // ColumnUnknown Chris@1319: cpc->addItem(tr("Time")); // ColumnStartTime Chris@1319: cpc->addItem(tr("End time")); // ColumnEndTime Chris@1319: cpc->addItem(tr("Duration")); // ColumnDuration Chris@1319: cpc->addItem(tr("Value")); // ColumnValue Chris@1319: cpc->addItem(tr("Pitch")); // ColumnPitch Chris@1319: cpc->addItem(tr("Label")); // ColumnLabel Chris@1319: cpc->setCurrentIndex(int(m_format.getColumnPurpose(i))); Chris@1318: Chris@581: for (int j = 0; j < example.size() && j < 6; ++j) { Chris@866: if (i >= example[j].size()) { Chris@866: continue; Chris@866: } Chris@581: QLabel *label = new QLabel; Chris@581: label->setTextFormat(Qt::PlainText); Chris@674: QString text = TextAbbrev::abbreviate(example[j][i], 35); Chris@674: label->setText(text); Chris@581: label->setFont(fp); Chris@581: label->setPalette(palette); Chris@581: label->setIndent(8); Chris@581: exampleLayout->addWidget(label, j+1, i); Chris@560: } Chris@560: } Chris@560: Chris@1413: if (m_exampleFrame) { Chris@1413: delete m_exampleFrame; Chris@1413: } Chris@1413: m_exampleFrame = exampleFrame; Chris@1413: Chris@1413: layout->addWidget(exampleFrame, m_exampleFrameRow, 0, 1, 4); Chris@560: layout->setColumnStretch(3, 10); Chris@1413: layout->setRowStretch(m_exampleFrameRow, 10); Chris@1319: Chris@1319: m_initialTimingOption = TimingImplicit; Chris@1319: if (m_format.getTimingType() == CSVFormat::ExplicitTiming) { Chris@1319: switch (m_format.getTimeUnits()) { Chris@1319: case CSVFormat::TimeSeconds: Chris@1319: m_initialTimingOption = TimingExplicitSeconds; break; Chris@1319: case CSVFormat::TimeMilliseconds: Chris@1319: m_initialTimingOption = TimingExplicitMsec; break; Chris@1319: case CSVFormat::TimeAudioFrames: Chris@1319: m_initialTimingOption = TimingExplicitSamples; break; Chris@1319: case CSVFormat::TimeWindows: Chris@1319: m_initialTimingOption = TimingImplicit; break; Chris@1318: } Chris@959: } Chris@1319: m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption)); Chris@378: Chris@807: for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) { Chris@1266: if (sampleRates[i] == m_format.getSampleRate()) { Chris@560: m_sampleRateCombo->setCurrentIndex(i); Chris@560: } Chris@378: } Chris@1318: Chris@1319: for (int i = 0; i <= 16; ++i) { Chris@1319: int value = 1 << i; Chris@1319: if (value == int(m_format.getWindowSize())) { Chris@1319: m_windowSizeCombo->setCurrentIndex(i); Chris@1319: } Chris@1319: } Chris@378: Chris@1319: timingTypeChanged(m_timingTypeCombo->currentIndex()); Chris@378: } Chris@378: Chris@378: CSVFormat Chris@378: CSVFormatDialog::getFormat() const Chris@378: { Chris@560: return m_format; Chris@378: } Chris@378: Chris@378: void Chris@561: CSVFormatDialog::updateModelLabel() Chris@378: { Chris@1318: if (!m_modelLabel) { Chris@1318: return; Chris@1318: } Chris@1318: Chris@561: LayerFactory *f = LayerFactory::getInstance(); Chris@561: Chris@561: QString s; Chris@561: switch (m_format.getModelType()) { Chris@561: case CSVFormat::OneDimensionalModel: Chris@561: s = f->getLayerPresentationName(LayerFactory::TimeInstants); Chris@561: break; Chris@561: case CSVFormat::TwoDimensionalModel: Chris@561: s = f->getLayerPresentationName(LayerFactory::TimeValues); Chris@561: break; Chris@561: case CSVFormat::TwoDimensionalModelWithDuration: Chris@561: s = f->getLayerPresentationName(LayerFactory::Regions); Chris@561: break; Chris@763: case CSVFormat::TwoDimensionalModelWithDurationAndPitch: Chris@763: s = f->getLayerPresentationName(LayerFactory::Notes); Chris@763: break; Chris@1521: case CSVFormat::TwoDimensionalModelWithDurationAndExtent: Chris@1521: s = f->getLayerPresentationName(LayerFactory::Boxes); Chris@1521: break; Chris@561: case CSVFormat::ThreeDimensionalModel: Chris@561: s = f->getLayerPresentationName(LayerFactory::Colour3DPlot); Chris@561: break; Chris@1312: case CSVFormat::WaveFileModel: Chris@1312: s = f->getLayerPresentationName(LayerFactory::Waveform); Chris@1312: break; Chris@561: } Chris@561: Chris@1318: m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.") Chris@1318: .arg(s)); Chris@378: } Chris@378: Chris@378: void Chris@959: CSVFormatDialog::applyStartTimePurpose() Chris@959: { Chris@971: // First check if we already have any. NB there may be fewer than Chris@971: // m_format.getColumnCount() elements in m_columnPurposeCombos Chris@992: // (because of the fuzzy column behaviour). Note also that the Chris@992: // fuzzy column (which is the one just showing how many more Chris@992: // columns there are) has a different combo with only two items Chris@992: // (ignore or Values) Chris@971: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@992: if (i == m_fuzzyColumn) continue; Chris@959: QComboBox *cb = m_columnPurposeCombos[i]; Chris@959: if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) { Chris@959: return; Chris@959: } Chris@959: } Chris@959: // and if not, select one Chris@971: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@992: if (i == m_fuzzyColumn) continue; Chris@959: QComboBox *cb = m_columnPurposeCombos[i]; Chris@959: if (cb->currentIndex() == int(CSVFormat::ColumnValue)) { Chris@959: cb->setCurrentIndex(int(CSVFormat::ColumnStartTime)); Chris@959: return; Chris@959: } Chris@959: } Chris@959: } Chris@959: Chris@959: void Chris@959: CSVFormatDialog::removeStartTimePurpose() Chris@959: { Chris@971: // NB there may be fewer than m_format.getColumnCount() elements Chris@971: // in m_columnPurposeCombos (because of the fuzzy column Chris@971: // behaviour) Chris@971: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@992: if (i == m_fuzzyColumn) continue; Chris@959: QComboBox *cb = m_columnPurposeCombos[i]; Chris@959: if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) { Chris@959: cb->setCurrentIndex(int(CSVFormat::ColumnValue)); Chris@959: } Chris@959: } Chris@959: } Chris@959: Chris@959: void Chris@959: CSVFormatDialog::updateComboVisibility() Chris@959: { Chris@1319: bool wantRate = (m_format.getTimingType() == CSVFormat::ImplicitTiming || Chris@959: m_format.getTimeUnits() == CSVFormat::TimeAudioFrames); Chris@959: bool wantWindow = (m_format.getTimingType() == CSVFormat::ImplicitTiming); Chris@959: Chris@959: m_sampleRateCombo->setEnabled(wantRate); Chris@959: m_sampleRateLabel->setEnabled(wantRate); Chris@959: Chris@1319: m_windowSizeCombo->setEnabled(wantWindow); Chris@1319: m_windowSizeLabel->setEnabled(wantWindow); Chris@959: } Chris@959: Chris@959: void Chris@1413: CSVFormatDialog::separatorChanged(QString sep) Chris@1413: { Chris@1413: if (sep == "" || m_csvFilePath == "") { Chris@1413: return; Chris@1413: } Chris@1413: Chris@1413: m_format.setSeparator(sep[0]); Chris@1413: m_format.guessFormatFor(m_csvFilePath); Chris@1413: Chris@1413: repopulate(); Chris@1413: } Chris@1413: Chris@1413: void Chris@378: CSVFormatDialog::timingTypeChanged(int type) Chris@378: { Chris@959: // Update any column purpose combos Chris@959: if (TimingOption(type) == TimingImplicit) { Chris@959: removeStartTimePurpose(); Chris@959: } else { Chris@959: applyStartTimePurpose(); Chris@378: } Chris@959: updateFormatFromDialog(); Chris@959: updateComboVisibility(); Chris@559: } Chris@559: Chris@559: void Chris@378: CSVFormatDialog::sampleRateChanged(QString rateString) Chris@378: { Chris@378: bool ok = false; Chris@378: int sampleRate = rateString.toInt(&ok); Chris@560: if (ok) m_format.setSampleRate(sampleRate); Chris@378: } Chris@378: Chris@378: void Chris@378: CSVFormatDialog::windowSizeChanged(QString sizeString) Chris@378: { Chris@378: bool ok = false; Chris@378: int size = sizeString.toInt(&ok); Chris@560: if (ok) m_format.setWindowSize(size); Chris@378: } Chris@560: Chris@560: void Chris@561: CSVFormatDialog::columnPurposeChanged(int p) Chris@560: { Chris@560: QObject *o = sender(); Chris@560: QComboBox *cb = qobject_cast(o); Chris@560: if (!cb) return; Chris@561: Chris@1319: // Ensure a consistent set of column purposes, in case of a Chris@1319: // situation where some combinations are contradictory. Only Chris@1319: // updates the UI, does not update the stored format record from Chris@1319: // the UI - that's the job of updateFormatFromDialog Chris@1318: Chris@561: CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p; Chris@561: Chris@959: bool haveStartTime = false; // so as to update timing type combo appropriately Chris@959: Chris@959: // Ensure the column purpose combos are consistent with one Chris@959: // another, without reference to m_format (which we'll update Chris@959: // separately) Chris@959: Chris@560: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@561: Chris@992: // The fuzzy column combo only has the entries or Chris@992: // Values, so it can't affect the timing type and none of this Chris@992: // logic affects it Chris@992: if (i == m_fuzzyColumn) continue; Chris@992: Chris@959: QComboBox *thisCombo = m_columnPurposeCombos[i]; Chris@561: Chris@959: CSVFormat::ColumnPurpose cp = (CSVFormat::ColumnPurpose) Chris@959: (thisCombo->currentIndex()); Chris@959: bool thisChanged = (cb == thisCombo); Chris@959: Chris@959: if (!thisChanged) { Chris@561: Chris@561: // We can only have one ColumnStartTime column, and only Chris@561: // one of either ColumnDuration or ColumnEndTime Chris@561: Chris@561: if (purpose == CSVFormat::ColumnStartTime) { Chris@561: if (cp == purpose) { Chris@561: cp = CSVFormat::ColumnValue; Chris@561: } Chris@561: } else if (purpose == CSVFormat::ColumnDuration || Chris@561: purpose == CSVFormat::ColumnEndTime) { Chris@561: if (cp == CSVFormat::ColumnDuration || Chris@561: cp == CSVFormat::ColumnEndTime) { Chris@561: cp = CSVFormat::ColumnValue; Chris@561: } Chris@561: } Chris@561: Chris@561: // And we can only have one label Chris@561: if (purpose == CSVFormat::ColumnLabel) { Chris@561: if (cp == purpose) { Chris@561: cp = CSVFormat::ColumnUnknown; Chris@561: } Chris@561: } Chris@959: Chris@959: if (cp == CSVFormat::ColumnStartTime) { Chris@959: haveStartTime = true; Chris@959: } Chris@959: Chris@959: thisCombo->setCurrentIndex(int(cp)); Chris@959: Chris@959: } else { Chris@959: if (purpose == CSVFormat::ColumnStartTime) { Chris@959: haveStartTime = true; Chris@959: } Chris@561: } Chris@959: } Chris@561: Chris@1319: if (!haveStartTime) { Chris@1319: m_timingTypeCombo->setCurrentIndex(int(TimingImplicit)); Chris@1319: } else if (m_timingTypeCombo->currentIndex() == int(TimingImplicit)) { Chris@1319: if (m_initialTimingOption == TimingImplicit) { Chris@1319: m_timingTypeCombo->setCurrentIndex(TimingExplicitSeconds); Chris@1319: } else { Chris@1319: m_timingTypeCombo->setCurrentIndex(m_initialTimingOption); Chris@959: } Chris@959: } Chris@1319: Chris@1319: updateFormatFromDialog(); Chris@1319: updateComboVisibility(); Chris@959: } Chris@1318: Chris@959: void Chris@959: CSVFormatDialog::updateFormatFromDialog() Chris@959: { Chris@1319: switch (TimingOption(m_timingTypeCombo->currentIndex())) { Chris@959: Chris@1319: case TimingExplicitSeconds: Chris@1319: m_format.setTimingType(CSVFormat::ExplicitTiming); Chris@1319: m_format.setTimeUnits(CSVFormat::TimeSeconds); Chris@1319: break; Chris@1319: Chris@1319: case TimingExplicitMsec: Chris@1319: m_format.setTimingType(CSVFormat::ExplicitTiming); Chris@1319: m_format.setTimeUnits(CSVFormat::TimeMilliseconds); Chris@1319: break; Chris@1319: Chris@1319: case TimingExplicitSamples: Chris@1319: m_format.setTimingType(CSVFormat::ExplicitTiming); Chris@1319: m_format.setTimeUnits(CSVFormat::TimeAudioFrames); Chris@1319: break; Chris@1319: Chris@1319: case TimingImplicit: Chris@1318: m_format.setTimingType(CSVFormat::ImplicitTiming); Chris@1319: m_format.setTimeUnits(CSVFormat::TimeWindows); Chris@1319: break; Chris@959: } Chris@1318: Chris@959: bool haveStartTime = false; Chris@959: bool haveDuration = false; Chris@959: bool havePitch = false; Chris@959: int valueCount = 0; Chris@959: Chris@959: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@959: Chris@959: QComboBox *thisCombo = m_columnPurposeCombos[i]; Chris@959: Chris@1319: CSVFormat::ColumnPurpose purpose = Chris@1319: (CSVFormat::ColumnPurpose) (thisCombo->currentIndex()); Chris@1319: Chris@959: if (i == m_fuzzyColumn) { Chris@992: for (int j = i; j < m_format.getColumnCount(); ++j) { Chris@959: if (purpose == CSVFormat::ColumnUnknown) { Chris@959: m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown); Chris@959: } else { // Value Chris@959: m_format.setColumnPurpose(j, CSVFormat::ColumnValue); Chris@959: ++valueCount; Chris@959: } Chris@959: } Chris@992: } else { Chris@992: Chris@992: if (purpose == CSVFormat::ColumnStartTime) { Chris@992: haveStartTime = true; Chris@992: } Chris@992: if (purpose == CSVFormat::ColumnEndTime || Chris@992: purpose == CSVFormat::ColumnDuration) { Chris@992: haveDuration = true; Chris@992: } Chris@992: if (purpose == CSVFormat::ColumnPitch) { Chris@992: havePitch = true; Chris@992: } Chris@992: if (purpose == CSVFormat::ColumnValue) { Chris@992: ++valueCount; Chris@992: } Chris@992: Chris@992: m_format.setColumnPurpose(i, purpose); Chris@959: } Chris@561: } Chris@561: Chris@1319: if (haveStartTime && haveDuration) { Chris@763: if (havePitch) { Chris@763: m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch); Chris@1521: } else if (valueCount == 2) { Chris@1521: m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndExtent); Chris@763: } else { Chris@763: m_format.setModelType(CSVFormat::TwoDimensionalModelWithDuration); Chris@763: } Chris@561: } else { Chris@561: if (valueCount > 1) { Chris@561: m_format.setModelType(CSVFormat::ThreeDimensionalModel); Chris@561: } else if (valueCount > 0) { Chris@561: m_format.setModelType(CSVFormat::TwoDimensionalModel); Chris@561: } else { Chris@561: m_format.setModelType(CSVFormat::OneDimensionalModel); Chris@560: } Chris@560: } Chris@561: Chris@561: updateModelLabel(); Chris@560: } Chris@560: Chris@560: Chris@959: