comparison widgets/CSVFormatDialog.cpp @ 959:2633a1d73e39

Address #1214, layer import produces wrong layer type. We needed a more principled approach to making sure the format gets updated properly and the dialog elements are consistent (basically separating making the dialog elements consistent from subsequently updating the format). This change should provide that, though there may be gotchas still.
author Chris Cannam
date Tue, 12 May 2015 12:31:37 +0100
parents 50be12cf2802
children fd934705973f
comparison
equal deleted inserted replaced
947:e53a87a5efb2 959:2633a1d73e39
119 layout->setRowStretch(row++, 10); 119 layout->setRowStretch(row++, 10);
120 120
121 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0); 121 layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
122 122
123 m_timingTypeCombo = new QComboBox; 123 m_timingTypeCombo = new QComboBox;
124 m_timingTypeCombo->addItem(tr("Explicitly, in seconds")); 124
125 m_timingTypeCombo->addItem(tr("Explicitly, in milliseconds")); 125 m_timingLabels = {
126 m_timingTypeCombo->addItem(tr("Explicitly, in audio sample frames")); 126 { TimingExplicitSeconds, tr("Explicitly, in seconds") },
127 m_timingTypeCombo->addItem(tr("Implicitly: rows are equally spaced in time")); 127 { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
128 { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
129 { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
130 };
131
132 for (auto &l: m_timingLabels) {
133 m_timingTypeCombo->addItem(l.second);
134 }
135
128 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2); 136 layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
137
129 connect(m_timingTypeCombo, SIGNAL(activated(int)), 138 connect(m_timingTypeCombo, SIGNAL(activated(int)),
130 this, SLOT(timingTypeChanged(int))); 139 this, SLOT(timingTypeChanged(int)));
131 m_timingTypeCombo->setCurrentIndex 140
132 (m_format.getTimingType() == CSVFormat::ExplicitTiming ? 141 m_initialTimingOption = TimingImplicit;
133 m_format.getTimeUnits() == CSVFormat::TimeSeconds ? 0 : 2 : 3); 142 if (m_format.getTimingType() == CSVFormat::ExplicitTiming) {
143 switch (m_format.getTimeUnits()) {
144 case CSVFormat::TimeSeconds:
145 m_initialTimingOption = TimingExplicitSeconds; break;
146 case CSVFormat::TimeMilliseconds:
147 m_initialTimingOption = TimingExplicitMsec; break;
148 case CSVFormat::TimeAudioFrames:
149 m_initialTimingOption = TimingExplicitSamples; break;
150 case CSVFormat::TimeWindows:
151 m_initialTimingOption = TimingImplicit; break;
152 }
153 }
154 m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption));
134 155
135 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):")); 156 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
136 layout->addWidget(m_sampleRateLabel, row, 0); 157 layout->addWidget(m_sampleRateLabel, row, 0);
137 158
138 int sampleRates[] = { 159 int sampleRates[] = {
187 connect(bb, SIGNAL(rejected()), this, SLOT(reject())); 208 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
188 209
189 setLayout(layout); 210 setLayout(layout);
190 211
191 timingTypeChanged(m_timingTypeCombo->currentIndex()); 212 timingTypeChanged(m_timingTypeCombo->currentIndex());
192 updateModelLabel();
193 } 213 }
194 214
195 CSVFormatDialog::~CSVFormatDialog() 215 CSVFormatDialog::~CSVFormatDialog()
196 { 216 {
197 } 217 }
228 248
229 m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.").arg(s)); 249 m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.").arg(s));
230 } 250 }
231 251
232 void 252 void
253 CSVFormatDialog::applyStartTimePurpose()
254 {
255 // First check if we already have any
256 for (int i = 0; i < m_format.getColumnCount(); ++i) {
257 QComboBox *cb = m_columnPurposeCombos[i];
258 if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) {
259 return;
260 }
261 }
262 // and if not, select one
263 for (int i = 0; i < m_format.getColumnCount(); ++i) {
264 QComboBox *cb = m_columnPurposeCombos[i];
265 if (cb->currentIndex() == int(CSVFormat::ColumnValue)) {
266 cb->setCurrentIndex(int(CSVFormat::ColumnStartTime));
267 return;
268 }
269 }
270 }
271
272 void
273 CSVFormatDialog::removeStartTimePurpose()
274 {
275 for (int i = 0; i < m_format.getColumnCount(); ++i) {
276 QComboBox *cb = m_columnPurposeCombos[i];
277 if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) {
278 cb->setCurrentIndex(int(CSVFormat::ColumnValue));
279 }
280 }
281 }
282
283 void
284 CSVFormatDialog::updateComboVisibility()
285 {
286 bool wantRate = (m_format.getTimingType() == CSVFormat::ImplicitTiming ||
287 m_format.getTimeUnits() == CSVFormat::TimeAudioFrames);
288 bool wantWindow = (m_format.getTimingType() == CSVFormat::ImplicitTiming);
289
290 m_sampleRateCombo->setEnabled(wantRate);
291 m_sampleRateLabel->setEnabled(wantRate);
292
293 m_windowSizeCombo->setEnabled(wantWindow);
294 m_windowSizeLabel->setEnabled(wantWindow);
295 }
296
297 void
233 CSVFormatDialog::timingTypeChanged(int type) 298 CSVFormatDialog::timingTypeChanged(int type)
234 { 299 {
235 switch (type) { 300 // Update any column purpose combos
236 301 if (TimingOption(type) == TimingImplicit) {
237 case 0: 302 removeStartTimePurpose();
238 m_format.setTimingType(CSVFormat::ExplicitTiming); 303 } else {
239 m_format.setTimeUnits(CSVFormat::TimeSeconds); 304 applyStartTimePurpose();
240 m_sampleRateCombo->setEnabled(false); 305 }
241 m_sampleRateLabel->setEnabled(false); 306 updateFormatFromDialog();
242 m_windowSizeCombo->setEnabled(false); 307 updateComboVisibility();
243 m_windowSizeLabel->setEnabled(false);
244 break;
245
246 case 1:
247 m_format.setTimingType(CSVFormat::ExplicitTiming);
248 m_format.setTimeUnits(CSVFormat::TimeMilliseconds);
249 m_sampleRateCombo->setEnabled(true);
250 m_sampleRateLabel->setEnabled(true);
251 m_windowSizeCombo->setEnabled(false);
252 m_windowSizeLabel->setEnabled(false);
253 break;
254
255 case 2:
256 m_format.setTimingType(CSVFormat::ExplicitTiming);
257 m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
258 m_sampleRateCombo->setEnabled(true);
259 m_sampleRateLabel->setEnabled(true);
260 m_windowSizeCombo->setEnabled(false);
261 m_windowSizeLabel->setEnabled(false);
262 break;
263
264 case 3:
265 m_format.setTimingType(CSVFormat::ImplicitTiming);
266 m_format.setTimeUnits(CSVFormat::TimeWindows);
267 m_sampleRateCombo->setEnabled(true);
268 m_sampleRateLabel->setEnabled(true);
269 m_windowSizeCombo->setEnabled(true);
270 m_windowSizeLabel->setEnabled(true);
271 break;
272 }
273 } 308 }
274 309
275 void 310 void
276 CSVFormatDialog::sampleRateChanged(QString rateString) 311 CSVFormatDialog::sampleRateChanged(QString rateString)
277 { 312 {
290 325
291 void 326 void
292 CSVFormatDialog::columnPurposeChanged(int p) 327 CSVFormatDialog::columnPurposeChanged(int p)
293 { 328 {
294 QObject *o = sender(); 329 QObject *o = sender();
295
296 QComboBox *cb = qobject_cast<QComboBox *>(o); 330 QComboBox *cb = qobject_cast<QComboBox *>(o);
297 if (!cb) return; 331 if (!cb) return;
298 332
299 CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p; 333 CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p;
300 334
301 bool haveStartTime = false; 335 bool haveStartTime = false; // so as to update timing type combo appropriately
302 bool haveDuration = false; 336
303 bool havePitch = false; 337 // Ensure the column purpose combos are consistent with one
304 int valueCount = 0; 338 // another, without reference to m_format (which we'll update
305 339 // separately)
340
306 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { 341 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
307 342
308 CSVFormat::ColumnPurpose cp = m_format.getColumnPurpose(i); 343 QComboBox *thisCombo = m_columnPurposeCombos[i];
309
310 bool thisChanged = (cb == m_columnPurposeCombos[i]);
311 344
312 if (thisChanged) { 345 CSVFormat::ColumnPurpose cp = (CSVFormat::ColumnPurpose)
313 346 (thisCombo->currentIndex());
314 cerr << "i == " << i << ", fuzzy == " << m_fuzzyColumn 347 bool thisChanged = (cb == thisCombo);
315 << ", p == " << p << endl; 348
316 349 if (!thisChanged) {
317 if (i == m_fuzzyColumn) {
318 for (int j = i; j < m_format.getColumnCount(); ++j) {
319 if (p == 0) { // Ignore
320 m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown);
321 } else { // Value
322 m_format.setColumnPurpose(j, CSVFormat::ColumnValue);
323 ++valueCount;
324 }
325 }
326 continue;
327 }
328
329 cp = purpose;
330
331 } else {
332 350
333 if (i == m_fuzzyColumn) continue; 351 if (i == m_fuzzyColumn) continue;
334 352
335 // We can only have one ColumnStartTime column, and only 353 // We can only have one ColumnStartTime column, and only
336 // one of either ColumnDuration or ColumnEndTime 354 // one of either ColumnDuration or ColumnEndTime
351 if (purpose == CSVFormat::ColumnLabel) { 369 if (purpose == CSVFormat::ColumnLabel) {
352 if (cp == purpose) { 370 if (cp == purpose) {
353 cp = CSVFormat::ColumnUnknown; 371 cp = CSVFormat::ColumnUnknown;
354 } 372 }
355 } 373 }
356 } 374
357 375 if (cp == CSVFormat::ColumnStartTime) {
358 if (cp == CSVFormat::ColumnStartTime) { 376 haveStartTime = true;
377 }
378
379 thisCombo->setCurrentIndex(int(cp));
380
381 } else {
382 if (purpose == CSVFormat::ColumnStartTime) {
383 haveStartTime = true;
384 }
385 }
386 }
387
388 if (!haveStartTime) {
389 m_timingTypeCombo->setCurrentIndex(int(TimingImplicit));
390 } else if (m_timingTypeCombo->currentIndex() == int(TimingImplicit)) {
391 if (m_initialTimingOption == TimingImplicit) {
392 m_timingTypeCombo->setCurrentIndex(TimingExplicitSeconds);
393 } else {
394 m_timingTypeCombo->setCurrentIndex(m_initialTimingOption);
395 }
396 }
397
398 updateFormatFromDialog();
399 updateComboVisibility();
400 }
401
402 void
403 CSVFormatDialog::updateFormatFromDialog()
404 {
405 switch (TimingOption(m_timingTypeCombo->currentIndex())) {
406
407 case TimingExplicitSeconds:
408 m_format.setTimingType(CSVFormat::ExplicitTiming);
409 m_format.setTimeUnits(CSVFormat::TimeSeconds);
410 break;
411
412 case TimingExplicitMsec:
413 m_format.setTimingType(CSVFormat::ExplicitTiming);
414 m_format.setTimeUnits(CSVFormat::TimeMilliseconds);
415 break;
416
417 case TimingExplicitSamples:
418 m_format.setTimingType(CSVFormat::ExplicitTiming);
419 m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
420 break;
421
422 case TimingImplicit:
423 m_format.setTimingType(CSVFormat::ImplicitTiming);
424 m_format.setTimeUnits(CSVFormat::TimeWindows);
425 break;
426 }
427
428 bool haveStartTime = false;
429 bool haveDuration = false;
430 bool havePitch = false;
431 int valueCount = 0;
432
433 for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
434
435 QComboBox *thisCombo = m_columnPurposeCombos[i];
436
437 CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)
438 (thisCombo->currentIndex());
439
440 if (purpose == CSVFormat::ColumnStartTime) {
359 haveStartTime = true; 441 haveStartTime = true;
360 } 442 }
361 if (cp == CSVFormat::ColumnEndTime || 443 if (purpose == CSVFormat::ColumnEndTime ||
362 cp == CSVFormat::ColumnDuration) { 444 purpose == CSVFormat::ColumnDuration) {
363 haveDuration = true; 445 haveDuration = true;
364 } 446 }
365 if (cp == CSVFormat::ColumnPitch) { 447 if (purpose == CSVFormat::ColumnPitch) {
366 havePitch = true; 448 havePitch = true;
367 } 449 }
368 if (cp == CSVFormat::ColumnValue) { 450 if (purpose == CSVFormat::ColumnValue) {
369 ++valueCount; 451 ++valueCount;
370 } 452 }
371 453
372 m_columnPurposeCombos[i]->setCurrentIndex(int(cp)); 454 m_format.setColumnPurpose(i, purpose);
373 m_format.setColumnPurpose(i, cp); 455
374 } 456 if (i == m_fuzzyColumn) {
375 457 for (int j = i + 1; j < m_format.getColumnCount(); ++j) {
376 if (!haveStartTime) { 458 if (purpose == CSVFormat::ColumnUnknown) {
377 m_timingTypeCombo->setCurrentIndex(2); 459 m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown);
378 timingTypeChanged(2); 460 } else { // Value
461 m_format.setColumnPurpose(j, CSVFormat::ColumnValue);
462 ++valueCount;
463 }
464 }
465 }
379 } 466 }
380 467
381 if (haveStartTime && haveDuration) { 468 if (haveStartTime && haveDuration) {
382 if (havePitch) { 469 if (havePitch) {
383 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch); 470 m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch);
396 483
397 updateModelLabel(); 484 updateModelLabel();
398 } 485 }
399 486
400 487
488