annotate widgets/CSVFormatDialog.cpp @ 855:57efeb75880d

Simplify some logic where loop was used with an unconditional "break" that meant it could only happen once (from coverity scan)
author Chris Cannam
date Wed, 03 Sep 2014 12:05:45 +0100
parents e4773943c9c1
children de9472751d31
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@378 7 This file copyright 2006 Chris Cannam.
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@378 33
Chris@682 34 #include "base/Debug.h"
Chris@682 35
Chris@581 36 CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format,
Chris@581 37 int maxDisplayCols) :
Chris@378 38 QDialog(parent),
Chris@581 39 m_format(format),
Chris@581 40 m_maxDisplayCols(maxDisplayCols),
Chris@581 41 m_fuzzyColumn(-1)
Chris@378 42 {
Chris@378 43 setModal(true);
Chris@378 44 setWindowTitle(tr("Select Data Format"));
Chris@378 45
Chris@378 46 QGridLayout *layout = new QGridLayout;
Chris@378 47
Chris@560 48 int row = 0;
Chris@378 49
Chris@560 50 layout->addWidget(new QLabel(tr("Please select the correct data format for this file.")),
Chris@560 51 row++, 0, 1, 4);
Chris@560 52
Chris@560 53 QFrame *exampleFrame = new QFrame;
Chris@560 54 exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@560 55 exampleFrame->setLineWidth(2);
Chris@560 56 QGridLayout *exampleLayout = new QGridLayout;
Chris@561 57 exampleLayout->setSpacing(4);
Chris@560 58 exampleFrame->setLayout(exampleLayout);
Chris@560 59
Chris@560 60 QPalette palette = exampleFrame->palette();
Chris@560 61 palette.setColor(QPalette::Window, palette.color(QPalette::Base));
Chris@560 62 exampleFrame->setPalette(palette);
Chris@560 63
Chris@560 64 QFont fp;
Chris@561 65 fp.setPointSize(fp.pointSize() * 0.9);
Chris@561 66 // fp.setFixedPitch(true);
Chris@561 67 // fp.setStyleHint(QFont::TypeWriter);
Chris@561 68 // fp.setFamily("Monospaced");
Chris@560 69
Chris@560 70 int columns = format.getColumnCount();
Chris@560 71 QList<QStringList> example = m_format.getExample();
Chris@560 72
Chris@560 73 for (int i = 0; i < columns; ++i) {
Chris@581 74
Chris@560 75 QComboBox *cpc = new QComboBox;
Chris@560 76 m_columnPurposeCombos.push_back(cpc);
Chris@560 77 exampleLayout->addWidget(cpc, 0, i);
Chris@581 78 connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int)));
Chris@581 79
Chris@581 80 if (i == m_maxDisplayCols && columns > i + 2) {
Chris@581 81 m_fuzzyColumn = i;
Chris@581 82 cpc->addItem(tr("<ignore>"));
Chris@581 83 cpc->addItem(tr("Values"));
Chris@581 84 cpc->setCurrentIndex
Chris@581 85 (m_format.getColumnPurpose(i-1) == CSVFormat::ColumnUnknown ? 0 : 1);
Chris@581 86 exampleLayout->addWidget(new QLabel(tr("(%1 more)").arg(columns - i)),
Chris@581 87 1, i);
Chris@581 88 break;
Chris@581 89 }
Chris@560 90
Chris@560 91 // NB must be in the same order as the CSVFormat::ColumnPurpose enum
Chris@560 92 cpc->addItem(tr("<ignore>")); // ColumnUnknown
Chris@560 93 cpc->addItem(tr("Time")); // ColumnStartTime
Chris@560 94 cpc->addItem(tr("End time")); // ColumnEndTime
Chris@560 95 cpc->addItem(tr("Duration")); // ColumnDuration
Chris@560 96 cpc->addItem(tr("Value")); // ColumnValue
Chris@763 97 cpc->addItem(tr("Pitch")); // ColumnPitch
Chris@560 98 cpc->addItem(tr("Label")); // ColumnLabel
Chris@560 99 cpc->setCurrentIndex(int(m_format.getColumnPurpose(i)));
Chris@560 100
Chris@581 101 for (int j = 0; j < example.size() && j < 6; ++j) {
Chris@581 102 QLabel *label = new QLabel;
Chris@581 103 label->setTextFormat(Qt::PlainText);
Chris@674 104 QString text = TextAbbrev::abbreviate(example[j][i], 35);
Chris@674 105 label->setText(text);
Chris@581 106 label->setFont(fp);
Chris@581 107 label->setPalette(palette);
Chris@581 108 label->setIndent(8);
Chris@581 109 exampleLayout->addWidget(label, j+1, i);
Chris@560 110 }
Chris@560 111 }
Chris@560 112
Chris@560 113 layout->addWidget(exampleFrame, row, 0, 1, 4);
Chris@560 114 layout->setColumnStretch(3, 10);
Chris@560 115 layout->setRowStretch(row++, 10);
Chris@560 116
Chris@560 117 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
Chris@378 118
Chris@378 119 m_timingTypeCombo = new QComboBox;
Chris@560 120 m_timingTypeCombo->addItem(tr("Explicitly, in seconds"));
Chris@560 121 m_timingTypeCombo->addItem(tr("Explicitly, in audio sample frames"));
Chris@560 122 m_timingTypeCombo->addItem(tr("Implicitly: rows are equally spaced in time"));
Chris@560 123 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
Chris@378 124 connect(m_timingTypeCombo, SIGNAL(activated(int)),
Chris@378 125 this, SLOT(timingTypeChanged(int)));
Chris@560 126 m_timingTypeCombo->setCurrentIndex
Chris@560 127 (m_format.getTimingType() == CSVFormat::ExplicitTiming ?
Chris@560 128 m_format.getTimeUnits() == CSVFormat::TimeSeconds ? 0 : 1 : 2);
Chris@559 129
Chris@378 130 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
Chris@560 131 layout->addWidget(m_sampleRateLabel, row, 0);
Chris@378 132
Chris@807 133 int sampleRates[] = {
Chris@378 134 8000, 11025, 12000, 22050, 24000, 32000,
Chris@378 135 44100, 48000, 88200, 96000, 176400, 192000
Chris@378 136 };
Chris@378 137
Chris@378 138 m_sampleRateCombo = new QComboBox;
Chris@807 139 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
Chris@378 140 m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
Chris@560 141 if (sampleRates[i] == m_format.getSampleRate()) {
Chris@560 142 m_sampleRateCombo->setCurrentIndex(i);
Chris@560 143 }
Chris@378 144 }
Chris@378 145 m_sampleRateCombo->setEditable(true);
Chris@378 146
Chris@560 147 layout->addWidget(m_sampleRateCombo, row++, 1);
Chris@378 148 connect(m_sampleRateCombo, SIGNAL(activated(QString)),
Chris@378 149 this, SLOT(sampleRateChanged(QString)));
Chris@378 150 connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
Chris@378 151 this, SLOT(sampleRateChanged(QString)));
Chris@378 152
Chris@378 153 m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
Chris@560 154 layout->addWidget(m_windowSizeLabel, row, 0);
Chris@378 155
Chris@378 156 m_windowSizeCombo = new QComboBox;
Chris@378 157 for (int i = 0; i <= 16; ++i) {
Chris@378 158 int value = 1 << i;
Chris@378 159 m_windowSizeCombo->addItem(QString("%1").arg(value));
Chris@560 160 if (value == int(m_format.getWindowSize())) {
Chris@560 161 m_windowSizeCombo->setCurrentIndex(i);
Chris@560 162 }
Chris@378 163 }
Chris@378 164 m_windowSizeCombo->setEditable(true);
Chris@378 165
Chris@560 166 layout->addWidget(m_windowSizeCombo, row++, 1);
Chris@378 167 connect(m_windowSizeCombo, SIGNAL(activated(QString)),
Chris@378 168 this, SLOT(windowSizeChanged(QString)));
Chris@378 169 connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
Chris@378 170 this, SLOT(windowSizeChanged(QString)));
Chris@378 171
Chris@561 172 m_modelLabel = new QLabel;
Chris@561 173 QFont f(m_modelLabel->font());
Chris@561 174 f.setItalic(true);
Chris@561 175 m_modelLabel->setFont(f);
Chris@561 176 layout->addWidget(m_modelLabel, row++, 0, 1, 4);
Chris@561 177
Chris@512 178 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
Chris@512 179 QDialogButtonBox::Cancel);
Chris@560 180 layout->addWidget(bb, row++, 0, 1, 4);
Chris@512 181 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
Chris@512 182 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
Chris@378 183
Chris@512 184 setLayout(layout);
Chris@378 185
Chris@378 186 timingTypeChanged(m_timingTypeCombo->currentIndex());
Chris@561 187 updateModelLabel();
Chris@378 188 }
Chris@378 189
Chris@378 190 CSVFormatDialog::~CSVFormatDialog()
Chris@378 191 {
Chris@378 192 }
Chris@378 193
Chris@378 194 CSVFormat
Chris@378 195 CSVFormatDialog::getFormat() const
Chris@378 196 {
Chris@560 197 return m_format;
Chris@378 198 }
Chris@378 199
Chris@378 200 void
Chris@561 201 CSVFormatDialog::updateModelLabel()
Chris@378 202 {
Chris@561 203 LayerFactory *f = LayerFactory::getInstance();
Chris@561 204
Chris@561 205 QString s;
Chris@561 206 switch (m_format.getModelType()) {
Chris@561 207 case CSVFormat::OneDimensionalModel:
Chris@561 208 s = f->getLayerPresentationName(LayerFactory::TimeInstants);
Chris@561 209 break;
Chris@561 210 case CSVFormat::TwoDimensionalModel:
Chris@561 211 s = f->getLayerPresentationName(LayerFactory::TimeValues);
Chris@561 212 break;
Chris@561 213 case CSVFormat::TwoDimensionalModelWithDuration:
Chris@561 214 s = f->getLayerPresentationName(LayerFactory::Regions);
Chris@561 215 break;
Chris@763 216 case CSVFormat::TwoDimensionalModelWithDurationAndPitch:
Chris@763 217 s = f->getLayerPresentationName(LayerFactory::Notes);
Chris@763 218 break;
Chris@561 219 case CSVFormat::ThreeDimensionalModel:
Chris@561 220 s = f->getLayerPresentationName(LayerFactory::Colour3DPlot);
Chris@561 221 break;
Chris@561 222 }
Chris@561 223
Chris@578 224 m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.").arg(s));
Chris@378 225 }
Chris@378 226
Chris@378 227 void
Chris@378 228 CSVFormatDialog::timingTypeChanged(int type)
Chris@378 229 {
Chris@378 230 switch (type) {
Chris@378 231
Chris@378 232 case 0:
Chris@560 233 m_format.setTimingType(CSVFormat::ExplicitTiming);
Chris@560 234 m_format.setTimeUnits(CSVFormat::TimeSeconds);
Chris@378 235 m_sampleRateCombo->setEnabled(false);
Chris@378 236 m_sampleRateLabel->setEnabled(false);
Chris@378 237 m_windowSizeCombo->setEnabled(false);
Chris@378 238 m_windowSizeLabel->setEnabled(false);
Chris@378 239 break;
Chris@378 240
Chris@378 241 case 1:
Chris@560 242 m_format.setTimingType(CSVFormat::ExplicitTiming);
Chris@560 243 m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
Chris@378 244 m_sampleRateCombo->setEnabled(true);
Chris@378 245 m_sampleRateLabel->setEnabled(true);
Chris@378 246 m_windowSizeCombo->setEnabled(false);
Chris@378 247 m_windowSizeLabel->setEnabled(false);
Chris@378 248 break;
Chris@378 249
Chris@378 250 case 2:
Chris@560 251 m_format.setTimingType(CSVFormat::ImplicitTiming);
Chris@560 252 m_format.setTimeUnits(CSVFormat::TimeWindows);
Chris@378 253 m_sampleRateCombo->setEnabled(true);
Chris@378 254 m_sampleRateLabel->setEnabled(true);
Chris@378 255 m_windowSizeCombo->setEnabled(true);
Chris@378 256 m_windowSizeLabel->setEnabled(true);
Chris@378 257 break;
Chris@378 258 }
Chris@559 259 }
Chris@559 260
Chris@559 261 void
Chris@378 262 CSVFormatDialog::sampleRateChanged(QString rateString)
Chris@378 263 {
Chris@378 264 bool ok = false;
Chris@378 265 int sampleRate = rateString.toInt(&ok);
Chris@560 266 if (ok) m_format.setSampleRate(sampleRate);
Chris@378 267 }
Chris@378 268
Chris@378 269 void
Chris@378 270 CSVFormatDialog::windowSizeChanged(QString sizeString)
Chris@378 271 {
Chris@378 272 bool ok = false;
Chris@378 273 int size = sizeString.toInt(&ok);
Chris@560 274 if (ok) m_format.setWindowSize(size);
Chris@378 275 }
Chris@560 276
Chris@560 277 void
Chris@561 278 CSVFormatDialog::columnPurposeChanged(int p)
Chris@560 279 {
Chris@560 280 QObject *o = sender();
Chris@561 281
Chris@560 282 QComboBox *cb = qobject_cast<QComboBox *>(o);
Chris@560 283 if (!cb) return;
Chris@561 284
Chris@561 285 CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p;
Chris@561 286
Chris@561 287 bool haveStartTime = false;
Chris@561 288 bool haveDuration = false;
Chris@763 289 bool havePitch = false;
Chris@561 290 int valueCount = 0;
Chris@561 291
Chris@560 292 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
Chris@561 293
Chris@561 294 CSVFormat::ColumnPurpose cp = m_format.getColumnPurpose(i);
Chris@561 295
Chris@561 296 bool thisChanged = (cb == m_columnPurposeCombos[i]);
Chris@561 297
Chris@561 298 if (thisChanged) {
Chris@561 299
Chris@682 300 cerr << "i == " << i << ", fuzzy == " << m_fuzzyColumn
Chris@682 301 << ", p == " << p << endl;
Chris@581 302
Chris@581 303 if (i == m_fuzzyColumn) {
Chris@581 304 for (int j = i; j < m_format.getColumnCount(); ++j) {
Chris@581 305 if (p == 0) { // Ignore
Chris@581 306 m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown);
Chris@581 307 } else { // Value
Chris@581 308 m_format.setColumnPurpose(j, CSVFormat::ColumnValue);
Chris@581 309 ++valueCount;
Chris@581 310 }
Chris@581 311 }
Chris@581 312 continue;
Chris@581 313 }
Chris@581 314
Chris@561 315 cp = purpose;
Chris@561 316
Chris@561 317 } else {
Chris@561 318
Chris@581 319 if (i == m_fuzzyColumn) continue;
Chris@581 320
Chris@561 321 // We can only have one ColumnStartTime column, and only
Chris@561 322 // one of either ColumnDuration or ColumnEndTime
Chris@561 323
Chris@561 324 if (purpose == CSVFormat::ColumnStartTime) {
Chris@561 325 if (cp == purpose) {
Chris@561 326 cp = CSVFormat::ColumnValue;
Chris@561 327 }
Chris@561 328 } else if (purpose == CSVFormat::ColumnDuration ||
Chris@561 329 purpose == CSVFormat::ColumnEndTime) {
Chris@561 330 if (cp == CSVFormat::ColumnDuration ||
Chris@561 331 cp == CSVFormat::ColumnEndTime) {
Chris@561 332 cp = CSVFormat::ColumnValue;
Chris@561 333 }
Chris@561 334 }
Chris@561 335
Chris@561 336 // And we can only have one label
Chris@561 337 if (purpose == CSVFormat::ColumnLabel) {
Chris@561 338 if (cp == purpose) {
Chris@561 339 cp = CSVFormat::ColumnUnknown;
Chris@561 340 }
Chris@561 341 }
Chris@561 342 }
Chris@561 343
Chris@561 344 if (cp == CSVFormat::ColumnStartTime) {
Chris@561 345 haveStartTime = true;
Chris@561 346 }
Chris@561 347 if (cp == CSVFormat::ColumnEndTime ||
Chris@561 348 cp == CSVFormat::ColumnDuration) {
Chris@561 349 haveDuration = true;
Chris@561 350 }
Chris@763 351 if (cp == CSVFormat::ColumnPitch) {
Chris@763 352 havePitch = true;
Chris@763 353 }
Chris@561 354 if (cp == CSVFormat::ColumnValue) {
Chris@561 355 ++valueCount;
Chris@561 356 }
Chris@561 357
Chris@561 358 m_columnPurposeCombos[i]->setCurrentIndex(int(cp));
Chris@561 359 m_format.setColumnPurpose(i, cp);
Chris@561 360 }
Chris@561 361
Chris@561 362 if (!haveStartTime) {
Chris@561 363 m_timingTypeCombo->setCurrentIndex(2);
Chris@561 364 timingTypeChanged(2);
Chris@561 365 }
Chris@561 366
Chris@561 367 if (haveStartTime && haveDuration) {
Chris@763 368 if (havePitch) {
Chris@763 369 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch);
Chris@763 370 } else {
Chris@763 371 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDuration);
Chris@763 372 }
Chris@561 373 } else {
Chris@561 374 if (valueCount > 1) {
Chris@561 375 m_format.setModelType(CSVFormat::ThreeDimensionalModel);
Chris@561 376 } else if (valueCount > 0) {
Chris@561 377 m_format.setModelType(CSVFormat::TwoDimensionalModel);
Chris@561 378 } else {
Chris@561 379 m_format.setModelType(CSVFormat::OneDimensionalModel);
Chris@560 380 }
Chris@560 381 }
Chris@561 382
Chris@561 383 updateModelLabel();
Chris@560 384 }
Chris@560 385
Chris@560 386