| 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@378 | 18 #include <QFrame> | 
| Chris@378 | 19 #include <QGridLayout> | 
| Chris@378 | 20 #include <QPushButton> | 
| Chris@378 | 21 #include <QHBoxLayout> | 
| Chris@378 | 22 #include <QVBoxLayout> | 
| Chris@378 | 23 #include <QTableWidget> | 
| Chris@378 | 24 #include <QComboBox> | 
| Chris@378 | 25 #include <QLabel> | 
| Chris@512 | 26 #include <QDialogButtonBox> | 
| Chris@378 | 27 | 
| Chris@378 | 28 | 
| Chris@378 | 29 CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format, | 
| Chris@378 | 30 				 size_t defaultSampleRate) : | 
| Chris@378 | 31     QDialog(parent), | 
| Chris@378 | 32     m_modelType(CSVFormat::OneDimensionalModel), | 
| Chris@378 | 33     m_timingType(CSVFormat::ExplicitTiming), | 
| Chris@378 | 34     m_timeUnits(CSVFormat::TimeAudioFrames), | 
| Chris@378 | 35     m_separator(""), | 
| Chris@378 | 36     m_behaviour(QString::KeepEmptyParts) | 
| Chris@378 | 37 { | 
| Chris@378 | 38     setModal(true); | 
| Chris@378 | 39     setWindowTitle(tr("Select Data Format")); | 
| Chris@378 | 40 | 
| Chris@378 | 41     m_modelType = format.getModelType(); | 
| Chris@378 | 42     m_timingType = format.getTimingType(); | 
| Chris@378 | 43     m_timeUnits = format.getTimeUnits(); | 
| Chris@378 | 44     m_separator = format.getSeparator(); | 
| Chris@378 | 45     m_sampleRate = format.getSampleRate(); | 
| Chris@378 | 46     m_windowSize = format.getWindowSize(); | 
| Chris@378 | 47     m_behaviour = format.getSplitBehaviour(); | 
| Chris@378 | 48     m_example = format.getExample(); | 
| Chris@378 | 49     m_maxExampleCols = format.getMaxExampleCols(); | 
| Chris@378 | 50 | 
| Chris@378 | 51     QGridLayout *layout = new QGridLayout; | 
| Chris@378 | 52 | 
| Chris@378 | 53     layout->addWidget(new QLabel(tr("<b>Select Data Format</b><p>Please select the correct data format for this file.")), | 
| Chris@378 | 54 		      0, 0, 1, 4); | 
| Chris@378 | 55 | 
| Chris@378 | 56     layout->addWidget(new QLabel(tr("Each row specifies:")), 1, 0); | 
| Chris@378 | 57 | 
| Chris@378 | 58     m_modelTypeCombo = new QComboBox; | 
| Chris@378 | 59     m_modelTypeCombo->addItem(tr("A point in time")); | 
| Chris@378 | 60     m_modelTypeCombo->addItem(tr("A value at a time")); | 
| Chris@378 | 61     m_modelTypeCombo->addItem(tr("A set of values")); | 
| Chris@378 | 62     layout->addWidget(m_modelTypeCombo, 1, 1, 1, 2); | 
| Chris@378 | 63     connect(m_modelTypeCombo, SIGNAL(activated(int)), | 
| Chris@378 | 64 	    this, SLOT(modelTypeChanged(int))); | 
| Chris@378 | 65     m_modelTypeCombo->setCurrentIndex(int(m_modelType)); | 
| Chris@378 | 66 | 
| Chris@378 | 67     layout->addWidget(new QLabel(tr("The first column contains:")), 2, 0); | 
| Chris@378 | 68 | 
| Chris@378 | 69     m_timingTypeCombo = new QComboBox; | 
| Chris@378 | 70     m_timingTypeCombo->addItem(tr("Time, in seconds")); | 
| Chris@378 | 71     m_timingTypeCombo->addItem(tr("Time, in audio sample frames")); | 
| Chris@378 | 72     m_timingTypeCombo->addItem(tr("Data (rows are consecutive in time)")); | 
| Chris@378 | 73     layout->addWidget(m_timingTypeCombo, 2, 1, 1, 2); | 
| Chris@378 | 74     connect(m_timingTypeCombo, SIGNAL(activated(int)), | 
| Chris@378 | 75 	    this, SLOT(timingTypeChanged(int))); | 
| Chris@378 | 76     m_timingTypeCombo->setCurrentIndex(m_timingType == CSVFormat::ExplicitTiming ? | 
| Chris@378 | 77                                        m_timeUnits == CSVFormat::TimeSeconds ? 0 : 1 : 2); | 
| Chris@378 | 78 | 
| Chris@378 | 79     m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):")); | 
| Chris@378 | 80     layout->addWidget(m_sampleRateLabel, 3, 0); | 
| Chris@378 | 81 | 
| Chris@378 | 82     size_t sampleRates[] = { | 
| Chris@378 | 83 	8000, 11025, 12000, 22050, 24000, 32000, | 
| Chris@378 | 84 	44100, 48000, 88200, 96000, 176400, 192000 | 
| Chris@378 | 85     }; | 
| Chris@378 | 86 | 
| Chris@378 | 87     m_sampleRateCombo = new QComboBox; | 
| Chris@378 | 88     m_sampleRate = defaultSampleRate; | 
| Chris@378 | 89     for (size_t i = 0; i < sizeof(sampleRates) / sizeof(sampleRates[0]); ++i) { | 
| Chris@378 | 90 	m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i])); | 
| Chris@378 | 91 	if (sampleRates[i] == m_sampleRate) m_sampleRateCombo->setCurrentIndex(i); | 
| Chris@378 | 92     } | 
| Chris@378 | 93     m_sampleRateCombo->setEditable(true); | 
| Chris@378 | 94 | 
| Chris@378 | 95     layout->addWidget(m_sampleRateCombo, 3, 1); | 
| Chris@378 | 96     connect(m_sampleRateCombo, SIGNAL(activated(QString)), | 
| Chris@378 | 97 	    this, SLOT(sampleRateChanged(QString))); | 
| Chris@378 | 98     connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)), | 
| Chris@378 | 99 	    this, SLOT(sampleRateChanged(QString))); | 
| Chris@378 | 100 | 
| Chris@378 | 101     m_windowSizeLabel = new QLabel(tr("Frame increment between rows:")); | 
| Chris@378 | 102     layout->addWidget(m_windowSizeLabel, 4, 0); | 
| Chris@378 | 103 | 
| Chris@378 | 104     m_windowSizeCombo = new QComboBox; | 
| Chris@378 | 105     m_windowSize = 1024; | 
| Chris@378 | 106     for (int i = 0; i <= 16; ++i) { | 
| Chris@378 | 107 	int value = 1 << i; | 
| Chris@378 | 108 	m_windowSizeCombo->addItem(QString("%1").arg(value)); | 
| Chris@378 | 109 	if (value == int(m_windowSize)) m_windowSizeCombo->setCurrentIndex(i); | 
| Chris@378 | 110     } | 
| Chris@378 | 111     m_windowSizeCombo->setEditable(true); | 
| Chris@378 | 112 | 
| Chris@378 | 113     layout->addWidget(m_windowSizeCombo, 4, 1); | 
| Chris@378 | 114     connect(m_windowSizeCombo, SIGNAL(activated(QString)), | 
| Chris@378 | 115 	    this, SLOT(windowSizeChanged(QString))); | 
| Chris@378 | 116     connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)), | 
| Chris@378 | 117 	    this, SLOT(windowSizeChanged(QString))); | 
| Chris@378 | 118 | 
| Chris@378 | 119     layout->addWidget(new QLabel(tr("\nExample data from file:")), 5, 0, 1, 4); | 
| Chris@378 | 120 | 
| Chris@378 | 121     m_exampleWidget = new QTableWidget | 
| Chris@378 | 122 	(std::min(10, m_example.size()), m_maxExampleCols); | 
| Chris@378 | 123 | 
| Chris@378 | 124     layout->addWidget(m_exampleWidget, 6, 0, 1, 4); | 
| Chris@378 | 125     layout->setColumnStretch(3, 10); | 
| Chris@512 | 126     layout->setRowStretch(6, 10); | 
| Chris@378 | 127 | 
| Chris@512 | 128     QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok | | 
| Chris@512 | 129                                                 QDialogButtonBox::Cancel); | 
| Chris@512 | 130     layout->addWidget(bb, 7, 0, 1, 4); | 
| Chris@512 | 131     connect(bb, SIGNAL(accepted()), this, SLOT(accept())); | 
| Chris@512 | 132     connect(bb, SIGNAL(rejected()), this, SLOT(reject())); | 
| Chris@378 | 133 | 
| Chris@512 | 134     setLayout(layout); | 
| Chris@378 | 135 | 
| Chris@378 | 136     timingTypeChanged(m_timingTypeCombo->currentIndex()); | 
| Chris@378 | 137 } | 
| Chris@378 | 138 | 
| Chris@378 | 139 CSVFormatDialog::~CSVFormatDialog() | 
| Chris@378 | 140 { | 
| Chris@378 | 141 } | 
| Chris@378 | 142 | 
| Chris@378 | 143 CSVFormat | 
| Chris@378 | 144 CSVFormatDialog::getFormat() const | 
| Chris@378 | 145 { | 
| Chris@378 | 146     CSVFormat format; | 
| Chris@378 | 147     format.setModelType(m_modelType); | 
| Chris@378 | 148     format.setTimingType(m_timingType); | 
| Chris@378 | 149     format.setTimeUnits(m_timeUnits); | 
| Chris@378 | 150     format.setSeparator(m_separator); | 
| Chris@378 | 151     format.setSampleRate(m_sampleRate); | 
| Chris@378 | 152     format.setWindowSize(m_windowSize); | 
| Chris@378 | 153     format.setSplitBehaviour(m_behaviour); | 
| Chris@378 | 154     return format; | 
| Chris@378 | 155 } | 
| Chris@378 | 156 | 
| Chris@378 | 157 void | 
| Chris@378 | 158 CSVFormatDialog::populateExample() | 
| Chris@378 | 159 { | 
| Chris@378 | 160     m_exampleWidget->setColumnCount | 
| Chris@378 | 161         (m_timingType == CSVFormat::ExplicitTiming ? | 
| Chris@378 | 162 	 m_maxExampleCols - 1 : m_maxExampleCols); | 
| Chris@378 | 163 | 
| Chris@378 | 164     m_exampleWidget->setHorizontalHeaderLabels(QStringList()); | 
| Chris@378 | 165 | 
| Chris@378 | 166     for (int i = 0; i < m_example.size(); ++i) { | 
| Chris@378 | 167 	for (int j = 0; j < m_example[i].size(); ++j) { | 
| Chris@378 | 168 | 
| Chris@378 | 169 	    QTableWidgetItem *item = new QTableWidgetItem(m_example[i][j]); | 
| Chris@378 | 170 | 
| Chris@378 | 171 	    if (j == 0) { | 
| Chris@378 | 172 		if (m_timingType == CSVFormat::ExplicitTiming) { | 
| Chris@378 | 173 		    m_exampleWidget->setVerticalHeaderItem(i, item); | 
| Chris@378 | 174 		    continue; | 
| Chris@378 | 175 		} else { | 
| Chris@378 | 176 		    QTableWidgetItem *header = | 
| Chris@378 | 177 			new QTableWidgetItem(QString("%1").arg(i)); | 
| Chris@378 | 178 		    header->setFlags(Qt::ItemIsEnabled); | 
| Chris@378 | 179 		    m_exampleWidget->setVerticalHeaderItem(i, header); | 
| Chris@378 | 180 		} | 
| Chris@378 | 181 	    } | 
| Chris@378 | 182 	    int index = j; | 
| Chris@378 | 183 	    if (m_timingType == CSVFormat::ExplicitTiming) --index; | 
| Chris@378 | 184 	    item->setFlags(Qt::ItemIsEnabled); | 
| Chris@378 | 185 	    m_exampleWidget->setItem(i, index, item); | 
| Chris@378 | 186 	} | 
| Chris@378 | 187     } | 
| Chris@378 | 188 } | 
| Chris@378 | 189 | 
| Chris@378 | 190 void | 
| Chris@378 | 191 CSVFormatDialog::modelTypeChanged(int type) | 
| Chris@378 | 192 { | 
| Chris@378 | 193     m_modelType = (CSVFormat::ModelType)type; | 
| Chris@378 | 194 | 
| Chris@378 | 195     if (m_modelType == CSVFormat::ThreeDimensionalModel) { | 
| Chris@378 | 196         // We can't load 3d models with explicit timing, because the 3d | 
| Chris@378 | 197         // model is dense so we need a fixed sample increment | 
| Chris@378 | 198         m_timingTypeCombo->setCurrentIndex(2); | 
| Chris@378 | 199         timingTypeChanged(2); | 
| Chris@378 | 200     } | 
| Chris@378 | 201 } | 
| Chris@378 | 202 | 
| Chris@378 | 203 void | 
| Chris@378 | 204 CSVFormatDialog::timingTypeChanged(int type) | 
| Chris@378 | 205 { | 
| Chris@378 | 206     switch (type) { | 
| Chris@378 | 207 | 
| Chris@378 | 208     case 0: | 
| Chris@378 | 209 	m_timingType = CSVFormat::ExplicitTiming; | 
| Chris@378 | 210 	m_timeUnits = CSVFormat::TimeSeconds; | 
| Chris@378 | 211 	m_sampleRateCombo->setEnabled(false); | 
| Chris@378 | 212 	m_sampleRateLabel->setEnabled(false); | 
| Chris@378 | 213 	m_windowSizeCombo->setEnabled(false); | 
| Chris@378 | 214 	m_windowSizeLabel->setEnabled(false); | 
| Chris@378 | 215         if (m_modelType == CSVFormat::ThreeDimensionalModel) { | 
| Chris@378 | 216             m_modelTypeCombo->setCurrentIndex(1); | 
| Chris@378 | 217             modelTypeChanged(1); | 
| Chris@378 | 218         } | 
| Chris@378 | 219 	break; | 
| Chris@378 | 220 | 
| Chris@378 | 221     case 1: | 
| Chris@378 | 222 	m_timingType = CSVFormat::ExplicitTiming; | 
| Chris@378 | 223 	m_timeUnits = CSVFormat::TimeAudioFrames; | 
| Chris@378 | 224 	m_sampleRateCombo->setEnabled(true); | 
| Chris@378 | 225 	m_sampleRateLabel->setEnabled(true); | 
| Chris@378 | 226 	m_windowSizeCombo->setEnabled(false); | 
| Chris@378 | 227 	m_windowSizeLabel->setEnabled(false); | 
| Chris@378 | 228         if (m_modelType == CSVFormat::ThreeDimensionalModel) { | 
| Chris@378 | 229             m_modelTypeCombo->setCurrentIndex(1); | 
| Chris@378 | 230             modelTypeChanged(1); | 
| Chris@378 | 231         } | 
| Chris@378 | 232 	break; | 
| Chris@378 | 233 | 
| Chris@378 | 234     case 2: | 
| Chris@378 | 235 	m_timingType = CSVFormat::ImplicitTiming; | 
| Chris@378 | 236 	m_timeUnits = CSVFormat::TimeWindows; | 
| Chris@378 | 237 	m_sampleRateCombo->setEnabled(true); | 
| Chris@378 | 238 	m_sampleRateLabel->setEnabled(true); | 
| Chris@378 | 239 	m_windowSizeCombo->setEnabled(true); | 
| Chris@378 | 240 	m_windowSizeLabel->setEnabled(true); | 
| Chris@378 | 241 	break; | 
| Chris@378 | 242     } | 
| Chris@378 | 243 | 
| Chris@378 | 244     populateExample(); | 
| Chris@378 | 245 } | 
| Chris@378 | 246 | 
| Chris@378 | 247 void | 
| Chris@378 | 248 CSVFormatDialog::sampleRateChanged(QString rateString) | 
| Chris@378 | 249 { | 
| Chris@378 | 250     bool ok = false; | 
| Chris@378 | 251     int sampleRate = rateString.toInt(&ok); | 
| Chris@378 | 252     if (ok) m_sampleRate = sampleRate; | 
| Chris@378 | 253 } | 
| Chris@378 | 254 | 
| Chris@378 | 255 void | 
| Chris@378 | 256 CSVFormatDialog::windowSizeChanged(QString sizeString) | 
| Chris@378 | 257 { | 
| Chris@378 | 258     bool ok = false; | 
| Chris@378 | 259     int size = sizeString.toInt(&ok); | 
| Chris@378 | 260     if (ok) m_windowSize = size; | 
| Chris@378 | 261 } |