comparison widgets/CSVFormatDialog.cpp @ 1413:0930a27ebea2

Support changing the separator (if more than one plausible one is found) and repopulating the dialog
author Chris Cannam
date Wed, 09 Jan 2019 14:41:52 +0000
parents fbda05431ce0
children d3ef60b6ae93
comparison
equal deleted inserted replaced
1412:79032214f79d 1413:0930a27ebea2
32 #include <iostream> 32 #include <iostream>
33 #include <cmath> 33 #include <cmath>
34 34
35 #include "base/Debug.h" 35 #include "base/Debug.h"
36 36
37 CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format, 37 CSVFormatDialog::CSVFormatDialog(QWidget *parent,
38 CSVFormat format,
38 int maxDisplayCols) : 39 int maxDisplayCols) :
39 QDialog(parent), 40 QDialog(parent),
41 m_csvFilePath(""),
42 m_referenceSampleRate(0),
40 m_format(format), 43 m_format(format),
41 m_maxDisplayCols(maxDisplayCols), 44 m_maxDisplayCols(maxDisplayCols),
42 m_fuzzyColumn(-1) 45 m_fuzzyColumn(-1)
43 { 46 {
47 init();
48 }
49
50 CSVFormatDialog::CSVFormatDialog(QWidget *parent,
51 QString csvFilePath,
52 sv_samplerate_t referenceSampleRate,
53 int maxDisplayCols) :
54 QDialog(parent),
55 m_csvFilePath(csvFilePath),
56 m_referenceSampleRate(referenceSampleRate),
57 m_maxDisplayCols(maxDisplayCols),
58 m_fuzzyColumn(-1)
59 {
60 m_format = CSVFormat(csvFilePath);
61 m_format.setSampleRate(referenceSampleRate);
62 init();
63 }
64
65 CSVFormatDialog::~CSVFormatDialog()
66 {
67 }
68
69 static int sampleRates[] = {
70 8000, 11025, 12000, 22050, 24000, 32000,
71 44100, 48000, 88200, 96000, 176400, 192000
72 };
73
74 void
75 CSVFormatDialog::init()
76 {
44 setModal(true); 77 setModal(true);
45 setWindowTitle(tr("Select Data Format")); 78 setWindowTitle(tr("Select Data Format"));
46 79
47 QGridLayout *layout = new QGridLayout; 80 QGridLayout *layout = new QGridLayout;
48 81
49 int row = 0; 82 int row = 0;
50 83
51 layout->addWidget 84 layout->addWidget
52 (new QLabel(tr("Please select the correct data format for this file.")), 85 (new QLabel(tr("Please select the correct data format for this file.")),
53 row++, 0, 1, 4); 86 row++, 0, 1, 4);
87
88 m_exampleFrame = nullptr;
89 m_exampleFrameRow = row++;
90
91 std::set<QChar> plausible = m_format.getPlausibleSeparators();
92 SVDEBUG << "Have " << plausible.size() << " plausible separator(s)" << endl;
93
94 if (m_csvFilePath != "" && plausible.size() > 1) {
95 // can only update when separator changed if we still have a
96 // file to refer to
97 layout->addWidget(new QLabel(tr("Column separator:")), row, 0);
98 m_separatorCombo = new QComboBox;
99 for (QChar c: plausible) {
100 m_separatorCombo->addItem(QString(c));
101 if (c == m_format.getSeparator()) {
102 m_separatorCombo->setCurrentIndex(m_separatorCombo->count()-1);
103 }
104 }
105 m_separatorCombo->setEditable(false);
106
107 layout->addWidget(m_separatorCombo, row++, 1);
108 connect(m_separatorCombo, SIGNAL(activated(QString)),
109 this, SLOT(separatorChanged(QString)));
110 }
111
112 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
113
114 m_timingTypeCombo = new QComboBox;
115
116 m_timingLabels = {
117 { TimingExplicitSeconds, tr("Explicitly, in seconds") },
118 { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
119 { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
120 { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
121 };
122
123 for (auto &l: m_timingLabels) {
124 m_timingTypeCombo->addItem(l.second);
125 }
126
127 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
128
129 connect(m_timingTypeCombo, SIGNAL(activated(int)),
130 this, SLOT(timingTypeChanged(int)));
131
132 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
133 layout->addWidget(m_sampleRateLabel, row, 0);
134
135 m_sampleRateCombo = new QComboBox;
136 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
137 m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
138 }
139 m_sampleRateCombo->setEditable(true);
140
141 layout->addWidget(m_sampleRateCombo, row++, 1);
142 connect(m_sampleRateCombo, SIGNAL(activated(QString)),
143 this, SLOT(sampleRateChanged(QString)));
144 connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
145 this, SLOT(sampleRateChanged(QString)));
146
147 m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
148 layout->addWidget(m_windowSizeLabel, row, 0);
149
150 m_windowSizeCombo = new QComboBox;
151 for (int i = 0; i <= 16; ++i) {
152 int value = 1 << i;
153 m_windowSizeCombo->addItem(QString("%1").arg(value));
154 }
155 m_windowSizeCombo->setEditable(true);
156
157 layout->addWidget(m_windowSizeCombo, row++, 1);
158 connect(m_windowSizeCombo, SIGNAL(activated(QString)),
159 this, SLOT(windowSizeChanged(QString)));
160 connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
161 this, SLOT(windowSizeChanged(QString)));
162
163 m_modelLabel = new QLabel;
164 QFont f(m_modelLabel->font());
165 f.setItalic(true);
166 m_modelLabel->setFont(f);
167 layout->addWidget(m_modelLabel, row++, 0, 1, 4);
168
169 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
170 QDialogButtonBox::Cancel);
171 layout->addWidget(bb, row++, 0, 1, 4);
172 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
173 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
174
175 setLayout(layout);
176
177 repopulate();
178 }
179
180 void
181 CSVFormatDialog::repopulate()
182 {
183 SVCERR << "CSVFormatDialog::repopulate()" << endl;
184
185 QGridLayout *layout = qobject_cast<QGridLayout *>(this->layout());
54 186
55 QFrame *exampleFrame = new QFrame; 187 QFrame *exampleFrame = new QFrame;
56 exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); 188 exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
57 exampleFrame->setLineWidth(2); 189 exampleFrame->setLineWidth(2);
58 QGridLayout *exampleLayout = new QGridLayout; 190 QGridLayout *exampleLayout = new QGridLayout;
64 exampleFrame->setPalette(palette); 196 exampleFrame->setPalette(palette);
65 197
66 QFont fp; 198 QFont fp;
67 fp.setPointSize(int(floor(fp.pointSize() * 0.9))); 199 fp.setPointSize(int(floor(fp.pointSize() * 0.9)));
68 200
69 int columns = format.getColumnCount(); 201 int columns = m_format.getColumnCount();
70 QList<QStringList> example = m_format.getExample(); 202 QList<QStringList> example = m_format.getExample();
71 203
204 m_columnPurposeCombos.clear();
205
72 for (int i = 0; i < columns; ++i) { 206 for (int i = 0; i < columns; ++i) {
73 207
74 QComboBox *cpc = new QComboBox; 208 QComboBox *cpc = new QComboBox;
75 m_columnPurposeCombos.push_back(cpc); 209 m_columnPurposeCombos.push_back(cpc);
76 exampleLayout->addWidget(cpc, 0, i); 210 exampleLayout->addWidget(cpc, 0, i);
113 label->setIndent(8); 247 label->setIndent(8);
114 exampleLayout->addWidget(label, j+1, i); 248 exampleLayout->addWidget(label, j+1, i);
115 } 249 }
116 } 250 }
117 251
118 layout->addWidget(exampleFrame, row, 0, 1, 4); 252 if (m_exampleFrame) {
253 delete m_exampleFrame;
254 }
255 m_exampleFrame = exampleFrame;
256
257 layout->addWidget(exampleFrame, m_exampleFrameRow, 0, 1, 4);
119 layout->setColumnStretch(3, 10); 258 layout->setColumnStretch(3, 10);
120 layout->setRowStretch(row++, 10); 259 layout->setRowStretch(m_exampleFrameRow, 10);
121
122 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
123
124 m_timingTypeCombo = new QComboBox;
125
126 m_timingLabels = {
127 { TimingExplicitSeconds, tr("Explicitly, in seconds") },
128 { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
129 { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
130 { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
131 };
132
133 for (auto &l: m_timingLabels) {
134 m_timingTypeCombo->addItem(l.second);
135 }
136
137 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
138
139 connect(m_timingTypeCombo, SIGNAL(activated(int)),
140 this, SLOT(timingTypeChanged(int)));
141 260
142 m_initialTimingOption = TimingImplicit; 261 m_initialTimingOption = TimingImplicit;
143 if (m_format.getTimingType() == CSVFormat::ExplicitTiming) { 262 if (m_format.getTimingType() == CSVFormat::ExplicitTiming) {
144 switch (m_format.getTimeUnits()) { 263 switch (m_format.getTimeUnits()) {
145 case CSVFormat::TimeSeconds: 264 case CSVFormat::TimeSeconds:
151 case CSVFormat::TimeWindows: 270 case CSVFormat::TimeWindows:
152 m_initialTimingOption = TimingImplicit; break; 271 m_initialTimingOption = TimingImplicit; break;
153 } 272 }
154 } 273 }
155 m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption)); 274 m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption));
156 275
157 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
158 layout->addWidget(m_sampleRateLabel, row, 0);
159
160 int sampleRates[] = {
161 8000, 11025, 12000, 22050, 24000, 32000,
162 44100, 48000, 88200, 96000, 176400, 192000
163 };
164
165 m_sampleRateCombo = new QComboBox;
166 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) { 276 for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
167 m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
168 if (sampleRates[i] == m_format.getSampleRate()) { 277 if (sampleRates[i] == m_format.getSampleRate()) {
169 m_sampleRateCombo->setCurrentIndex(i); 278 m_sampleRateCombo->setCurrentIndex(i);
170 } 279 }
171 } 280 }
172 m_sampleRateCombo->setEditable(true); 281
173
174 layout->addWidget(m_sampleRateCombo, row++, 1);
175 connect(m_sampleRateCombo, SIGNAL(activated(QString)),
176 this, SLOT(sampleRateChanged(QString)));
177 connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
178 this, SLOT(sampleRateChanged(QString)));
179
180 m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
181 layout->addWidget(m_windowSizeLabel, row, 0);
182
183 m_windowSizeCombo = new QComboBox;
184 for (int i = 0; i <= 16; ++i) { 282 for (int i = 0; i <= 16; ++i) {
185 int value = 1 << i; 283 int value = 1 << i;
186 m_windowSizeCombo->addItem(QString("%1").arg(value));
187 if (value == int(m_format.getWindowSize())) { 284 if (value == int(m_format.getWindowSize())) {
188 m_windowSizeCombo->setCurrentIndex(i); 285 m_windowSizeCombo->setCurrentIndex(i);
189 } 286 }
190 } 287 }
191 m_windowSizeCombo->setEditable(true);
192
193 layout->addWidget(m_windowSizeCombo, row++, 1);
194 connect(m_windowSizeCombo, SIGNAL(activated(QString)),
195 this, SLOT(windowSizeChanged(QString)));
196 connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
197 this, SLOT(windowSizeChanged(QString)));
198
199 m_modelLabel = new QLabel;
200 QFont f(m_modelLabel->font());
201 f.setItalic(true);
202 m_modelLabel->setFont(f);
203 layout->addWidget(m_modelLabel, row++, 0, 1, 4);
204
205 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
206 QDialogButtonBox::Cancel);
207 layout->addWidget(bb, row++, 0, 1, 4);
208 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
209 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
210
211 setLayout(layout);
212 288
213 timingTypeChanged(m_timingTypeCombo->currentIndex()); 289 timingTypeChanged(m_timingTypeCombo->currentIndex());
214 }
215
216 CSVFormatDialog::~CSVFormatDialog()
217 {
218 } 290 }
219 291
220 CSVFormat 292 CSVFormat
221 CSVFormatDialog::getFormat() const 293 CSVFormatDialog::getFormat() const
222 { 294 {
313 m_windowSizeCombo->setEnabled(wantWindow); 385 m_windowSizeCombo->setEnabled(wantWindow);
314 m_windowSizeLabel->setEnabled(wantWindow); 386 m_windowSizeLabel->setEnabled(wantWindow);
315 } 387 }
316 388
317 void 389 void
390 CSVFormatDialog::separatorChanged(QString sep)
391 {
392 if (sep == "" || m_csvFilePath == "") {
393 return;
394 }
395
396 m_format.setSeparator(sep[0]);
397 m_format.guessFormatFor(m_csvFilePath);
398
399 repopulate();
400 }
401
402 void
318 CSVFormatDialog::timingTypeChanged(int type) 403 CSVFormatDialog::timingTypeChanged(int type)
319 { 404 {
320 // Update any column purpose combos 405 // Update any column purpose combos
321 if (TimingOption(type) == TimingImplicit) { 406 if (TimingOption(type) == TimingImplicit) {
322 removeStartTimePurpose(); 407 removeStartTimePurpose();