annotate widgets/CSVFormatDialog.cpp @ 1553:76e4302a3fc2

Fix note numbering - ensure stable across whole track (as it used to be, but without scanning all notes in paint in order to do that)
author Chris Cannam
date Fri, 22 Nov 2019 14:12:50 +0000
parents d3ef60b6ae93
children 129c704566ff
rev   line source
Chris@378 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@378 2
Chris@378 3 /*
Chris@378 4 Sonic Visualiser
Chris@378 5 An audio file viewer and annotation editor.
Chris@378 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1319 7 This file copyright 2006-2018 Chris Cannam and QMUL.
Chris@378 8
Chris@378 9 This program is free software; you can redistribute it and/or
Chris@378 10 modify it under the terms of the GNU General Public License as
Chris@378 11 published by the Free Software Foundation; either version 2 of the
Chris@378 12 License, or (at your option) any later version. See the file
Chris@378 13 COPYING included with this distribution for more information.
Chris@378 14 */
Chris@378 15
Chris@378 16 #include "CSVFormatDialog.h"
Chris@378 17
Chris@561 18 #include "layer/LayerFactory.h"
Chris@561 19
Chris@674 20 #include "TextAbbrev.h"
Chris@674 21
Chris@378 22 #include <QFrame>
Chris@378 23 #include <QGridLayout>
Chris@378 24 #include <QPushButton>
Chris@378 25 #include <QHBoxLayout>
Chris@378 26 #include <QVBoxLayout>
Chris@378 27 #include <QTableWidget>
Chris@378 28 #include <QComboBox>
Chris@378 29 #include <QLabel>
Chris@512 30 #include <QDialogButtonBox>
Chris@378 31
Chris@560 32 #include <iostream>
Chris@913 33 #include <cmath>
Chris@378 34
Chris@682 35 #include "base/Debug.h"
Chris@682 36
Chris@1413 37 CSVFormatDialog::CSVFormatDialog(QWidget *parent,
Chris@1413 38 CSVFormat format,
Chris@581 39 int maxDisplayCols) :
Chris@378 40 QDialog(parent),
Chris@1413 41 m_csvFilePath(""),
Chris@1413 42 m_referenceSampleRate(0),
Chris@581 43 m_format(format),
Chris@581 44 m_maxDisplayCols(maxDisplayCols),
Chris@581 45 m_fuzzyColumn(-1)
Chris@378 46 {
Chris@1413 47 init();
Chris@1413 48 }
Chris@1413 49
Chris@1413 50 CSVFormatDialog::CSVFormatDialog(QWidget *parent,
Chris@1413 51 QString csvFilePath,
Chris@1413 52 sv_samplerate_t referenceSampleRate,
Chris@1413 53 int maxDisplayCols) :
Chris@1413 54 QDialog(parent),
Chris@1413 55 m_csvFilePath(csvFilePath),
Chris@1413 56 m_referenceSampleRate(referenceSampleRate),
Chris@1413 57 m_maxDisplayCols(maxDisplayCols),
Chris@1413 58 m_fuzzyColumn(-1)
Chris@1413 59 {
Chris@1413 60 m_format = CSVFormat(csvFilePath);
Chris@1413 61 m_format.setSampleRate(referenceSampleRate);
Chris@1413 62 init();
Chris@1413 63 }
Chris@1413 64
Chris@1413 65 CSVFormatDialog::~CSVFormatDialog()
Chris@1413 66 {
Chris@1413 67 }
Chris@1413 68
Chris@1413 69 static int sampleRates[] = {
Chris@1413 70 8000, 11025, 12000, 22050, 24000, 32000,
Chris@1413 71 44100, 48000, 88200, 96000, 176400, 192000
Chris@1413 72 };
Chris@1413 73
Chris@1413 74 void
Chris@1413 75 CSVFormatDialog::init()
Chris@1413 76 {
Chris@378 77 setModal(true);
Chris@378 78 setWindowTitle(tr("Select Data Format"));
Chris@1413 79
Chris@378 80 QGridLayout *layout = new QGridLayout;
Chris@378 81
Chris@560 82 int row = 0;
Chris@378 83
Chris@1318 84 layout->addWidget
Chris@1318 85 (new QLabel(tr("Please select the correct data format for this file.")),
Chris@1318 86 row++, 0, 1, 4);
Chris@560 87
Chris@1413 88 m_exampleFrame = nullptr;
Chris@1413 89 m_exampleFrameRow = row++;
Chris@1413 90
Chris@1413 91 std::set<QChar> plausible = m_format.getPlausibleSeparators();
Chris@1413 92 SVDEBUG << "Have " << plausible.size() << " plausible separator(s)" << endl;
Chris@1413 93
Chris@1413 94 if (m_csvFilePath != "" && plausible.size() > 1) {
Chris@1413 95 // can only update when separator changed if we still have a
Chris@1413 96 // file to refer to
Chris@1413 97 layout->addWidget(new QLabel(tr("Column separator:")), row, 0);
Chris@1413 98 m_separatorCombo = new QComboBox;
Chris@1413 99 for (QChar c: plausible) {
Chris@1413 100 m_separatorCombo->addItem(QString(c));
Chris@1413 101 if (c == m_format.getSeparator()) {
Chris@1413 102 m_separatorCombo->setCurrentIndex(m_separatorCombo->count()-1);
Chris@1413 103 }
Chris@1413 104 }
Chris@1413 105 m_separatorCombo->setEditable(false);
Chris@1413 106
Chris@1413 107 layout->addWidget(m_separatorCombo, row++, 1);
Chris@1413 108 connect(m_separatorCombo, SIGNAL(activated(QString)),
Chris@1413 109 this, SLOT(separatorChanged(QString)));
Chris@1413 110 }
Chris@1413 111
Chris@1413 112 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
Chris@1413 113
Chris@1413 114 m_timingTypeCombo = new QComboBox;
Chris@1413 115
Chris@1413 116 m_timingLabels = {
Chris@1413 117 { TimingExplicitSeconds, tr("Explicitly, in seconds") },
Chris@1413 118 { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
Chris@1413 119 { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
Chris@1413 120 { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
Chris@1413 121 };
Chris@1413 122
Chris@1413 123 for (auto &l: m_timingLabels) {
Chris@1413 124 m_timingTypeCombo->addItem(l.second);
Chris@1413 125 }
Chris@1413 126
Chris@1413 127 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
Chris@1413 128
Chris@1413 129 connect(m_timingTypeCombo, SIGNAL(activated(int)),
Chris@1413 130 this, SLOT(timingTypeChanged(int)));
Chris@1413 131
Chris@1413 132 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
Chris@1413 133 layout->addWidget(m_sampleRateLabel, row, 0);
Chris@1413 134
Chris@1413 135 m_sampleRateCombo = new QComboBox;
Chris@1413 136 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
Chris@1413 137 m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
Chris@1413 138 }
Chris@1413 139 m_sampleRateCombo->setEditable(true);
Chris@1413 140
Chris@1413 141 layout->addWidget(m_sampleRateCombo, row++, 1);
Chris@1413 142 connect(m_sampleRateCombo, SIGNAL(activated(QString)),
Chris@1413 143 this, SLOT(sampleRateChanged(QString)));
Chris@1413 144 connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
Chris@1413 145 this, SLOT(sampleRateChanged(QString)));
Chris@1413 146
Chris@1413 147 m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
Chris@1413 148 layout->addWidget(m_windowSizeLabel, row, 0);
Chris@1413 149
Chris@1413 150 m_windowSizeCombo = new QComboBox;
Chris@1413 151 for (int i = 0; i <= 16; ++i) {
Chris@1413 152 int value = 1 << i;
Chris@1413 153 m_windowSizeCombo->addItem(QString("%1").arg(value));
Chris@1413 154 }
Chris@1413 155 m_windowSizeCombo->setEditable(true);
Chris@1413 156
Chris@1413 157 layout->addWidget(m_windowSizeCombo, row++, 1);
Chris@1413 158 connect(m_windowSizeCombo, SIGNAL(activated(QString)),
Chris@1413 159 this, SLOT(windowSizeChanged(QString)));
Chris@1413 160 connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
Chris@1413 161 this, SLOT(windowSizeChanged(QString)));
Chris@1413 162
Chris@1413 163 m_modelLabel = new QLabel;
Chris@1413 164 QFont f(m_modelLabel->font());
Chris@1413 165 f.setItalic(true);
Chris@1413 166 m_modelLabel->setFont(f);
Chris@1413 167 layout->addWidget(m_modelLabel, row++, 0, 1, 4);
Chris@1413 168
Chris@1413 169 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
Chris@1413 170 QDialogButtonBox::Cancel);
Chris@1413 171 layout->addWidget(bb, row++, 0, 1, 4);
Chris@1413 172 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
Chris@1413 173 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
Chris@1413 174
Chris@1413 175 setLayout(layout);
Chris@1413 176
Chris@1413 177 repopulate();
Chris@1413 178 }
Chris@1413 179
Chris@1413 180 void
Chris@1413 181 CSVFormatDialog::repopulate()
Chris@1413 182 {
Chris@1413 183 SVCERR << "CSVFormatDialog::repopulate()" << endl;
Chris@1413 184
Chris@1413 185 QGridLayout *layout = qobject_cast<QGridLayout *>(this->layout());
Chris@1413 186
Chris@560 187 QFrame *exampleFrame = new QFrame;
Chris@560 188 exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@560 189 exampleFrame->setLineWidth(2);
Chris@560 190 QGridLayout *exampleLayout = new QGridLayout;
Chris@561 191 exampleLayout->setSpacing(4);
Chris@560 192 exampleFrame->setLayout(exampleLayout);
Chris@560 193
Chris@560 194 QPalette palette = exampleFrame->palette();
Chris@560 195 palette.setColor(QPalette::Window, palette.color(QPalette::Base));
Chris@560 196 exampleFrame->setPalette(palette);
Chris@560 197
Chris@560 198 QFont fp;
Chris@908 199 fp.setPointSize(int(floor(fp.pointSize() * 0.9)));
Chris@560 200
Chris@1413 201 int columns = m_format.getColumnCount();
Chris@560 202 QList<QStringList> example = m_format.getExample();
Chris@560 203
Chris@1413 204 m_columnPurposeCombos.clear();
Chris@1413 205
Chris@560 206 for (int i = 0; i < columns; ++i) {
Chris@581 207
Chris@560 208 QComboBox *cpc = new QComboBox;
Chris@560 209 m_columnPurposeCombos.push_back(cpc);
Chris@560 210 exampleLayout->addWidget(cpc, 0, i);
Chris@581 211 connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int)));
Chris@1318 212
Chris@581 213 if (i == m_maxDisplayCols && columns > i + 2) {
Chris@581 214 m_fuzzyColumn = i;
Chris@1318 215
Chris@1319 216 cpc->addItem(tr("<ignore>"));
Chris@1319 217 cpc->addItem(tr("Values"));
Chris@1319 218 cpc->setCurrentIndex
Chris@1319 219 (m_format.getColumnPurpose(i-1) ==
Chris@1319 220 CSVFormat::ColumnUnknown ? 0 : 1);
Chris@1319 221
Chris@1318 222 exampleLayout->addWidget
Chris@1318 223 (new QLabel(tr("(%1 more)").arg(columns - i)), 1, i);
Chris@581 224 break;
Chris@581 225 }
Chris@560 226
Chris@1319 227 // NB must be in the same order as the CSVFormat::ColumnPurpose enum
Chris@1319 228 cpc->addItem(tr("<ignore>")); // ColumnUnknown
Chris@1319 229 cpc->addItem(tr("Time")); // ColumnStartTime
Chris@1319 230 cpc->addItem(tr("End time")); // ColumnEndTime
Chris@1319 231 cpc->addItem(tr("Duration")); // ColumnDuration
Chris@1319 232 cpc->addItem(tr("Value")); // ColumnValue
Chris@1319 233 cpc->addItem(tr("Pitch")); // ColumnPitch
Chris@1319 234 cpc->addItem(tr("Label")); // ColumnLabel
Chris@1319 235 cpc->setCurrentIndex(int(m_format.getColumnPurpose(i)));
Chris@1318 236
Chris@581 237 for (int j = 0; j < example.size() && j < 6; ++j) {
Chris@866 238 if (i >= example[j].size()) {
Chris@866 239 continue;
Chris@866 240 }
Chris@581 241 QLabel *label = new QLabel;
Chris@581 242 label->setTextFormat(Qt::PlainText);
Chris@674 243 QString text = TextAbbrev::abbreviate(example[j][i], 35);
Chris@674 244 label->setText(text);
Chris@581 245 label->setFont(fp);
Chris@581 246 label->setPalette(palette);
Chris@581 247 label->setIndent(8);
Chris@581 248 exampleLayout->addWidget(label, j+1, i);
Chris@560 249 }
Chris@560 250 }
Chris@560 251
Chris@1413 252 if (m_exampleFrame) {
Chris@1413 253 delete m_exampleFrame;
Chris@1413 254 }
Chris@1413 255 m_exampleFrame = exampleFrame;
Chris@1413 256
Chris@1413 257 layout->addWidget(exampleFrame, m_exampleFrameRow, 0, 1, 4);
Chris@560 258 layout->setColumnStretch(3, 10);
Chris@1413 259 layout->setRowStretch(m_exampleFrameRow, 10);
Chris@1319 260
Chris@1319 261 m_initialTimingOption = TimingImplicit;
Chris@1319 262 if (m_format.getTimingType() == CSVFormat::ExplicitTiming) {
Chris@1319 263 switch (m_format.getTimeUnits()) {
Chris@1319 264 case CSVFormat::TimeSeconds:
Chris@1319 265 m_initialTimingOption = TimingExplicitSeconds; break;
Chris@1319 266 case CSVFormat::TimeMilliseconds:
Chris@1319 267 m_initialTimingOption = TimingExplicitMsec; break;
Chris@1319 268 case CSVFormat::TimeAudioFrames:
Chris@1319 269 m_initialTimingOption = TimingExplicitSamples; break;
Chris@1319 270 case CSVFormat::TimeWindows:
Chris@1319 271 m_initialTimingOption = TimingImplicit; break;
Chris@1318 272 }
Chris@959 273 }
Chris@1319 274 m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption));
Chris@378 275
Chris@807 276 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
Chris@1266 277 if (sampleRates[i] == m_format.getSampleRate()) {
Chris@560 278 m_sampleRateCombo->setCurrentIndex(i);
Chris@560 279 }
Chris@378 280 }
Chris@1318 281
Chris@1319 282 for (int i = 0; i <= 16; ++i) {
Chris@1319 283 int value = 1 << i;
Chris@1319 284 if (value == int(m_format.getWindowSize())) {
Chris@1319 285 m_windowSizeCombo->setCurrentIndex(i);
Chris@1319 286 }
Chris@1319 287 }
Chris@378 288
Chris@1319 289 timingTypeChanged(m_timingTypeCombo->currentIndex());
Chris@378 290 }
Chris@378 291
Chris@378 292 CSVFormat
Chris@378 293 CSVFormatDialog::getFormat() const
Chris@378 294 {
Chris@560 295 return m_format;
Chris@378 296 }
Chris@378 297
Chris@378 298 void
Chris@561 299 CSVFormatDialog::updateModelLabel()
Chris@378 300 {
Chris@1318 301 if (!m_modelLabel) {
Chris@1318 302 return;
Chris@1318 303 }
Chris@1318 304
Chris@561 305 LayerFactory *f = LayerFactory::getInstance();
Chris@561 306
Chris@561 307 QString s;
Chris@561 308 switch (m_format.getModelType()) {
Chris@561 309 case CSVFormat::OneDimensionalModel:
Chris@561 310 s = f->getLayerPresentationName(LayerFactory::TimeInstants);
Chris@561 311 break;
Chris@561 312 case CSVFormat::TwoDimensionalModel:
Chris@561 313 s = f->getLayerPresentationName(LayerFactory::TimeValues);
Chris@561 314 break;
Chris@561 315 case CSVFormat::TwoDimensionalModelWithDuration:
Chris@561 316 s = f->getLayerPresentationName(LayerFactory::Regions);
Chris@561 317 break;
Chris@763 318 case CSVFormat::TwoDimensionalModelWithDurationAndPitch:
Chris@763 319 s = f->getLayerPresentationName(LayerFactory::Notes);
Chris@763 320 break;
Chris@1521 321 case CSVFormat::TwoDimensionalModelWithDurationAndExtent:
Chris@1521 322 s = f->getLayerPresentationName(LayerFactory::Boxes);
Chris@1521 323 break;
Chris@561 324 case CSVFormat::ThreeDimensionalModel:
Chris@561 325 s = f->getLayerPresentationName(LayerFactory::Colour3DPlot);
Chris@561 326 break;
Chris@1312 327 case CSVFormat::WaveFileModel:
Chris@1312 328 s = f->getLayerPresentationName(LayerFactory::Waveform);
Chris@1312 329 break;
Chris@561 330 }
Chris@561 331
Chris@1318 332 m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.")
Chris@1318 333 .arg(s));
Chris@378 334 }
Chris@378 335
Chris@378 336 void
Chris@959 337 CSVFormatDialog::applyStartTimePurpose()
Chris@959 338 {
Chris@971 339 // First check if we already have any. NB there may be fewer than
Chris@971 340 // m_format.getColumnCount() elements in m_columnPurposeCombos
Chris@992 341 // (because of the fuzzy column behaviour). Note also that the
Chris@992 342 // fuzzy column (which is the one just showing how many more
Chris@992 343 // columns there are) has a different combo with only two items
Chris@992 344 // (ignore or Values)
Chris@971 345 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@992 346 if (i == m_fuzzyColumn) continue;
Chris@959 347 QComboBox *cb = m_columnPurposeCombos[i];
Chris@959 348 if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) {
Chris@959 349 return;
Chris@959 350 }
Chris@959 351 }
Chris@959 352 // and if not, select one
Chris@971 353 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@992 354 if (i == m_fuzzyColumn) continue;
Chris@959 355 QComboBox *cb = m_columnPurposeCombos[i];
Chris@959 356 if (cb->currentIndex() == int(CSVFormat::ColumnValue)) {
Chris@959 357 cb->setCurrentIndex(int(CSVFormat::ColumnStartTime));
Chris@959 358 return;
Chris@959 359 }
Chris@959 360 }
Chris@959 361 }
Chris@959 362
Chris@959 363 void
Chris@959 364 CSVFormatDialog::removeStartTimePurpose()
Chris@959 365 {
Chris@971 366 // NB there may be fewer than m_format.getColumnCount() elements
Chris@971 367 // in m_columnPurposeCombos (because of the fuzzy column
Chris@971 368 // behaviour)
Chris@971 369 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@992 370 if (i == m_fuzzyColumn) continue;
Chris@959 371 QComboBox *cb = m_columnPurposeCombos[i];
Chris@959 372 if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) {
Chris@959 373 cb->setCurrentIndex(int(CSVFormat::ColumnValue));
Chris@959 374 }
Chris@959 375 }
Chris@959 376 }
Chris@959 377
Chris@959 378 void
Chris@959 379 CSVFormatDialog::updateComboVisibility()
Chris@959 380 {
Chris@1319 381 bool wantRate = (m_format.getTimingType() == CSVFormat::ImplicitTiming ||
Chris@959 382 m_format.getTimeUnits() == CSVFormat::TimeAudioFrames);
Chris@959 383 bool wantWindow = (m_format.getTimingType() == CSVFormat::ImplicitTiming);
Chris@959 384
Chris@959 385 m_sampleRateCombo->setEnabled(wantRate);
Chris@959 386 m_sampleRateLabel->setEnabled(wantRate);
Chris@959 387
Chris@1319 388 m_windowSizeCombo->setEnabled(wantWindow);
Chris@1319 389 m_windowSizeLabel->setEnabled(wantWindow);
Chris@959 390 }
Chris@959 391
Chris@959 392 void
Chris@1413 393 CSVFormatDialog::separatorChanged(QString sep)
Chris@1413 394 {
Chris@1413 395 if (sep == "" || m_csvFilePath == "") {
Chris@1413 396 return;
Chris@1413 397 }
Chris@1413 398
Chris@1413 399 m_format.setSeparator(sep[0]);
Chris@1413 400 m_format.guessFormatFor(m_csvFilePath);
Chris@1413 401
Chris@1413 402 repopulate();
Chris@1413 403 }
Chris@1413 404
Chris@1413 405 void
Chris@378 406 CSVFormatDialog::timingTypeChanged(int type)
Chris@378 407 {
Chris@959 408 // Update any column purpose combos
Chris@959 409 if (TimingOption(type) == TimingImplicit) {
Chris@959 410 removeStartTimePurpose();
Chris@959 411 } else {
Chris@959 412 applyStartTimePurpose();
Chris@378 413 }
Chris@959 414 updateFormatFromDialog();
Chris@959 415 updateComboVisibility();
Chris@559 416 }
Chris@559 417
Chris@559 418 void
Chris@378 419 CSVFormatDialog::sampleRateChanged(QString rateString)
Chris@378 420 {
Chris@378 421 bool ok = false;
Chris@378 422 int sampleRate = rateString.toInt(&ok);
Chris@560 423 if (ok) m_format.setSampleRate(sampleRate);
Chris@378 424 }
Chris@378 425
Chris@378 426 void
Chris@378 427 CSVFormatDialog::windowSizeChanged(QString sizeString)
Chris@378 428 {
Chris@378 429 bool ok = false;
Chris@378 430 int size = sizeString.toInt(&ok);
Chris@560 431 if (ok) m_format.setWindowSize(size);
Chris@378 432 }
Chris@560 433
Chris@560 434 void
Chris@561 435 CSVFormatDialog::columnPurposeChanged(int p)
Chris@560 436 {
Chris@560 437 QObject *o = sender();
Chris@560 438 QComboBox *cb = qobject_cast<QComboBox *>(o);
Chris@560 439 if (!cb) return;
Chris@561 440
Chris@1319 441 // Ensure a consistent set of column purposes, in case of a
Chris@1319 442 // situation where some combinations are contradictory. Only
Chris@1319 443 // updates the UI, does not update the stored format record from
Chris@1319 444 // the UI - that's the job of updateFormatFromDialog
Chris@1318 445
Chris@561 446 CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p;
Chris@561 447
Chris@959 448 bool haveStartTime = false; // so as to update timing type combo appropriately
Chris@959 449
Chris@959 450 // Ensure the column purpose combos are consistent with one
Chris@959 451 // another, without reference to m_format (which we'll update
Chris@959 452 // separately)
Chris@959 453
Chris@560 454 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@561 455
Chris@992 456 // The fuzzy column combo only has the entries <ignore> or
Chris@992 457 // Values, so it can't affect the timing type and none of this
Chris@992 458 // logic affects it
Chris@992 459 if (i == m_fuzzyColumn) continue;
Chris@992 460
Chris@959 461 QComboBox *thisCombo = m_columnPurposeCombos[i];
Chris@561 462
Chris@959 463 CSVFormat::ColumnPurpose cp = (CSVFormat::ColumnPurpose)
Chris@959 464 (thisCombo->currentIndex());
Chris@959 465 bool thisChanged = (cb == thisCombo);
Chris@959 466
Chris@959 467 if (!thisChanged) {
Chris@561 468
Chris@561 469 // We can only have one ColumnStartTime column, and only
Chris@561 470 // one of either ColumnDuration or ColumnEndTime
Chris@561 471
Chris@561 472 if (purpose == CSVFormat::ColumnStartTime) {
Chris@561 473 if (cp == purpose) {
Chris@561 474 cp = CSVFormat::ColumnValue;
Chris@561 475 }
Chris@561 476 } else if (purpose == CSVFormat::ColumnDuration ||
Chris@561 477 purpose == CSVFormat::ColumnEndTime) {
Chris@561 478 if (cp == CSVFormat::ColumnDuration ||
Chris@561 479 cp == CSVFormat::ColumnEndTime) {
Chris@561 480 cp = CSVFormat::ColumnValue;
Chris@561 481 }
Chris@561 482 }
Chris@561 483
Chris@561 484 // And we can only have one label
Chris@561 485 if (purpose == CSVFormat::ColumnLabel) {
Chris@561 486 if (cp == purpose) {
Chris@561 487 cp = CSVFormat::ColumnUnknown;
Chris@561 488 }
Chris@561 489 }
Chris@959 490
Chris@959 491 if (cp == CSVFormat::ColumnStartTime) {
Chris@959 492 haveStartTime = true;
Chris@959 493 }
Chris@959 494
Chris@959 495 thisCombo->setCurrentIndex(int(cp));
Chris@959 496
Chris@959 497 } else {
Chris@959 498 if (purpose == CSVFormat::ColumnStartTime) {
Chris@959 499 haveStartTime = true;
Chris@959 500 }
Chris@561 501 }
Chris@959 502 }
Chris@561 503
Chris@1319 504 if (!haveStartTime) {
Chris@1319 505 m_timingTypeCombo->setCurrentIndex(int(TimingImplicit));
Chris@1319 506 } else if (m_timingTypeCombo->currentIndex() == int(TimingImplicit)) {
Chris@1319 507 if (m_initialTimingOption == TimingImplicit) {
Chris@1319 508 m_timingTypeCombo->setCurrentIndex(TimingExplicitSeconds);
Chris@1319 509 } else {
Chris@1319 510 m_timingTypeCombo->setCurrentIndex(m_initialTimingOption);
Chris@959 511 }
Chris@959 512 }
Chris@1319 513
Chris@1319 514 updateFormatFromDialog();
Chris@1319 515 updateComboVisibility();
Chris@959 516 }
Chris@1318 517
Chris@959 518 void
Chris@959 519 CSVFormatDialog::updateFormatFromDialog()
Chris@959 520 {
Chris@1319 521 switch (TimingOption(m_timingTypeCombo->currentIndex())) {
Chris@959 522
Chris@1319 523 case TimingExplicitSeconds:
Chris@1319 524 m_format.setTimingType(CSVFormat::ExplicitTiming);
Chris@1319 525 m_format.setTimeUnits(CSVFormat::TimeSeconds);
Chris@1319 526 break;
Chris@1319 527
Chris@1319 528 case TimingExplicitMsec:
Chris@1319 529 m_format.setTimingType(CSVFormat::ExplicitTiming);
Chris@1319 530 m_format.setTimeUnits(CSVFormat::TimeMilliseconds);
Chris@1319 531 break;
Chris@1319 532
Chris@1319 533 case TimingExplicitSamples:
Chris@1319 534 m_format.setTimingType(CSVFormat::ExplicitTiming);
Chris@1319 535 m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
Chris@1319 536 break;
Chris@1319 537
Chris@1319 538 case TimingImplicit:
Chris@1318 539 m_format.setTimingType(CSVFormat::ImplicitTiming);
Chris@1319 540 m_format.setTimeUnits(CSVFormat::TimeWindows);
Chris@1319 541 break;
Chris@959 542 }
Chris@1318 543
Chris@959 544 bool haveStartTime = false;
Chris@959 545 bool haveDuration = false;
Chris@959 546 bool havePitch = false;
Chris@959 547 int valueCount = 0;
Chris@959 548
Chris@959 549 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@959 550
Chris@959 551 QComboBox *thisCombo = m_columnPurposeCombos[i];
Chris@959 552
Chris@1319 553 CSVFormat::ColumnPurpose purpose =
Chris@1319 554 (CSVFormat::ColumnPurpose) (thisCombo->currentIndex());
Chris@1319 555
Chris@959 556 if (i == m_fuzzyColumn) {
Chris@992 557 for (int j = i; j < m_format.getColumnCount(); ++j) {
Chris@959 558 if (purpose == CSVFormat::ColumnUnknown) {
Chris@959 559 m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown);
Chris@959 560 } else { // Value
Chris@959 561 m_format.setColumnPurpose(j, CSVFormat::ColumnValue);
Chris@959 562 ++valueCount;
Chris@959 563 }
Chris@959 564 }
Chris@992 565 } else {
Chris@992 566
Chris@992 567 if (purpose == CSVFormat::ColumnStartTime) {
Chris@992 568 haveStartTime = true;
Chris@992 569 }
Chris@992 570 if (purpose == CSVFormat::ColumnEndTime ||
Chris@992 571 purpose == CSVFormat::ColumnDuration) {
Chris@992 572 haveDuration = true;
Chris@992 573 }
Chris@992 574 if (purpose == CSVFormat::ColumnPitch) {
Chris@992 575 havePitch = true;
Chris@992 576 }
Chris@992 577 if (purpose == CSVFormat::ColumnValue) {
Chris@992 578 ++valueCount;
Chris@992 579 }
Chris@992 580
Chris@992 581 m_format.setColumnPurpose(i, purpose);
Chris@959 582 }
Chris@561 583 }
Chris@561 584
Chris@1319 585 if (haveStartTime && haveDuration) {
Chris@763 586 if (havePitch) {
Chris@763 587 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch);
Chris@1521 588 } else if (valueCount == 2) {
Chris@1521 589 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndExtent);
Chris@763 590 } else {
Chris@763 591 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDuration);
Chris@763 592 }
Chris@561 593 } else {
Chris@561 594 if (valueCount > 1) {
Chris@561 595 m_format.setModelType(CSVFormat::ThreeDimensionalModel);
Chris@561 596 } else if (valueCount > 0) {
Chris@561 597 m_format.setModelType(CSVFormat::TwoDimensionalModel);
Chris@561 598 } else {
Chris@561 599 m_format.setModelType(CSVFormat::OneDimensionalModel);
Chris@560 600 }
Chris@560 601 }
Chris@561 602
Chris@561 603 updateModelLabel();
Chris@560 604 }
Chris@560 605
Chris@560 606
Chris@959 607