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@378: This file copyright 2006 Chris Cannam. 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@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@378: Chris@560: CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format) : Chris@378: QDialog(parent), Chris@560: m_format(format) Chris@378: { Chris@378: setModal(true); Chris@378: setWindowTitle(tr("Select Data Format")); Chris@378: Chris@378: QGridLayout *layout = new QGridLayout; Chris@378: Chris@560: int row = 0; Chris@378: Chris@560: layout->addWidget(new QLabel(tr("Please select the correct data format for this file.")), Chris@560: row++, 0, 1, 4); Chris@560: 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@561: fp.setPointSize(fp.pointSize() * 0.9); Chris@561: // fp.setFixedPitch(true); Chris@561: // fp.setStyleHint(QFont::TypeWriter); Chris@561: // fp.setFamily("Monospaced"); Chris@560: Chris@560: int columns = format.getColumnCount(); Chris@560: QList example = m_format.getExample(); Chris@560: Chris@560: for (int i = 0; i < columns; ++i) { Chris@560: Chris@560: QComboBox *cpc = new QComboBox; Chris@560: m_columnPurposeCombos.push_back(cpc); Chris@560: exampleLayout->addWidget(cpc, 0, i); Chris@560: Chris@560: // NB must be in the same order as the CSVFormat::ColumnPurpose enum Chris@560: cpc->addItem(tr("")); // ColumnUnknown Chris@560: cpc->addItem(tr("Time")); // ColumnStartTime Chris@560: cpc->addItem(tr("End time")); // ColumnEndTime Chris@560: cpc->addItem(tr("Duration")); // ColumnDuration Chris@560: cpc->addItem(tr("Value")); // ColumnValue Chris@560: cpc->addItem(tr("Label")); // ColumnLabel Chris@560: cpc->setCurrentIndex(int(m_format.getColumnPurpose(i))); Chris@560: connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int))); Chris@560: Chris@560: if (i < m_format.getMaxExampleCols()) { Chris@560: for (int j = 0; j < example.size() && j < 6; ++j) { Chris@560: QLabel *label = new QLabel; Chris@560: label->setTextFormat(Qt::PlainText); Chris@560: label->setText(example[j][i]); Chris@560: label->setFont(fp); Chris@560: label->setPalette(palette); Chris@561: label->setIndent(8); Chris@560: exampleLayout->addWidget(label, j+1, i); Chris@560: } Chris@560: } Chris@560: } Chris@560: Chris@560: layout->addWidget(exampleFrame, row, 0, 1, 4); Chris@560: layout->setColumnStretch(3, 10); Chris@560: layout->setRowStretch(row++, 10); Chris@560: Chris@560: layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0); Chris@378: Chris@378: m_timingTypeCombo = new QComboBox; Chris@560: m_timingTypeCombo->addItem(tr("Explicitly, in seconds")); Chris@560: m_timingTypeCombo->addItem(tr("Explicitly, in audio sample frames")); Chris@560: m_timingTypeCombo->addItem(tr("Implicitly: rows are equally spaced in time")); Chris@560: layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2); Chris@378: connect(m_timingTypeCombo, SIGNAL(activated(int)), Chris@378: this, SLOT(timingTypeChanged(int))); Chris@560: m_timingTypeCombo->setCurrentIndex Chris@560: (m_format.getTimingType() == CSVFormat::ExplicitTiming ? Chris@560: m_format.getTimeUnits() == CSVFormat::TimeSeconds ? 0 : 1 : 2); Chris@559: Chris@378: m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):")); Chris@560: layout->addWidget(m_sampleRateLabel, row, 0); Chris@378: Chris@378: size_t sampleRates[] = { Chris@378: 8000, 11025, 12000, 22050, 24000, 32000, Chris@378: 44100, 48000, 88200, 96000, 176400, 192000 Chris@378: }; Chris@378: Chris@378: m_sampleRateCombo = new QComboBox; Chris@378: for (size_t i = 0; i < sizeof(sampleRates) / sizeof(sampleRates[0]); ++i) { Chris@378: m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i])); Chris@560: if (sampleRates[i] == m_format.getSampleRate()) { Chris@560: m_sampleRateCombo->setCurrentIndex(i); Chris@560: } Chris@378: } Chris@378: m_sampleRateCombo->setEditable(true); Chris@378: Chris@560: layout->addWidget(m_sampleRateCombo, row++, 1); Chris@378: connect(m_sampleRateCombo, SIGNAL(activated(QString)), Chris@378: this, SLOT(sampleRateChanged(QString))); Chris@378: connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)), Chris@378: this, SLOT(sampleRateChanged(QString))); Chris@378: Chris@378: m_windowSizeLabel = new QLabel(tr("Frame increment between rows:")); Chris@560: layout->addWidget(m_windowSizeLabel, row, 0); Chris@378: Chris@378: m_windowSizeCombo = new QComboBox; Chris@378: for (int i = 0; i <= 16; ++i) { Chris@378: int value = 1 << i; Chris@378: m_windowSizeCombo->addItem(QString("%1").arg(value)); Chris@560: if (value == int(m_format.getWindowSize())) { Chris@560: m_windowSizeCombo->setCurrentIndex(i); Chris@560: } Chris@378: } Chris@378: m_windowSizeCombo->setEditable(true); Chris@378: Chris@560: layout->addWidget(m_windowSizeCombo, row++, 1); Chris@378: connect(m_windowSizeCombo, SIGNAL(activated(QString)), Chris@378: this, SLOT(windowSizeChanged(QString))); Chris@378: connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)), Chris@378: this, SLOT(windowSizeChanged(QString))); Chris@378: Chris@561: m_modelLabel = new QLabel; Chris@561: QFont f(m_modelLabel->font()); Chris@561: f.setItalic(true); Chris@561: m_modelLabel->setFont(f); Chris@561: layout->addWidget(m_modelLabel, row++, 0, 1, 4); Chris@561: Chris@512: QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok | Chris@512: QDialogButtonBox::Cancel); Chris@560: layout->addWidget(bb, row++, 0, 1, 4); Chris@512: connect(bb, SIGNAL(accepted()), this, SLOT(accept())); Chris@512: connect(bb, SIGNAL(rejected()), this, SLOT(reject())); Chris@378: Chris@512: setLayout(layout); Chris@378: Chris@378: timingTypeChanged(m_timingTypeCombo->currentIndex()); Chris@561: updateModelLabel(); Chris@378: } Chris@378: Chris@378: CSVFormatDialog::~CSVFormatDialog() Chris@378: { 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@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@561: case CSVFormat::ThreeDimensionalModel: Chris@561: s = f->getLayerPresentationName(LayerFactory::Colour3DPlot); Chris@561: break; Chris@561: } Chris@561: Chris@561: m_modelLabel->setText("\n" + QString("Data will be displayed in a %1 layer.").arg(s)); Chris@378: } Chris@378: Chris@378: void Chris@378: CSVFormatDialog::timingTypeChanged(int type) Chris@378: { Chris@378: switch (type) { Chris@378: Chris@378: case 0: Chris@560: m_format.setTimingType(CSVFormat::ExplicitTiming); Chris@560: m_format.setTimeUnits(CSVFormat::TimeSeconds); Chris@378: m_sampleRateCombo->setEnabled(false); Chris@378: m_sampleRateLabel->setEnabled(false); Chris@378: m_windowSizeCombo->setEnabled(false); Chris@378: m_windowSizeLabel->setEnabled(false); Chris@378: break; Chris@378: Chris@378: case 1: Chris@560: m_format.setTimingType(CSVFormat::ExplicitTiming); Chris@560: m_format.setTimeUnits(CSVFormat::TimeAudioFrames); Chris@378: m_sampleRateCombo->setEnabled(true); Chris@378: m_sampleRateLabel->setEnabled(true); Chris@378: m_windowSizeCombo->setEnabled(false); Chris@378: m_windowSizeLabel->setEnabled(false); Chris@378: break; Chris@378: Chris@378: case 2: Chris@560: m_format.setTimingType(CSVFormat::ImplicitTiming); Chris@560: m_format.setTimeUnits(CSVFormat::TimeWindows); Chris@378: m_sampleRateCombo->setEnabled(true); Chris@378: m_sampleRateLabel->setEnabled(true); Chris@378: m_windowSizeCombo->setEnabled(true); Chris@378: m_windowSizeLabel->setEnabled(true); Chris@378: break; Chris@378: } 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@561: Chris@560: QComboBox *cb = qobject_cast(o); Chris@560: if (!cb) return; Chris@561: Chris@561: CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p; Chris@561: Chris@561: bool haveStartTime = false; Chris@561: bool haveDuration = false; Chris@561: int valueCount = 0; Chris@561: Chris@560: for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { Chris@561: Chris@561: CSVFormat::ColumnPurpose cp = m_format.getColumnPurpose(i); Chris@561: Chris@561: bool thisChanged = (cb == m_columnPurposeCombos[i]); Chris@561: Chris@561: if (thisChanged) { Chris@561: Chris@561: cp = purpose; Chris@561: Chris@561: } else { 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@561: } Chris@561: Chris@561: if (cp == CSVFormat::ColumnStartTime) { Chris@561: haveStartTime = true; Chris@561: } Chris@561: if (cp == CSVFormat::ColumnEndTime || Chris@561: cp == CSVFormat::ColumnDuration) { Chris@561: haveDuration = true; Chris@561: } Chris@561: if (cp == CSVFormat::ColumnValue) { Chris@561: ++valueCount; Chris@561: } Chris@561: Chris@561: m_columnPurposeCombos[i]->setCurrentIndex(int(cp)); Chris@561: m_format.setColumnPurpose(i, cp); Chris@561: } Chris@561: Chris@561: if (!haveStartTime) { Chris@561: m_timingTypeCombo->setCurrentIndex(2); Chris@561: timingTypeChanged(2); Chris@561: } Chris@561: Chris@561: if (haveStartTime && haveDuration) { Chris@561: m_format.setModelType(CSVFormat::TwoDimensionalModelWithDuration); 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: