svgui  1.9
CSVFormatDialog.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "CSVFormatDialog.h"
00017 
00018 #include "layer/LayerFactory.h"
00019 
00020 #include "TextAbbrev.h"
00021 
00022 #include <QFrame>
00023 #include <QGridLayout>
00024 #include <QPushButton>
00025 #include <QHBoxLayout>
00026 #include <QVBoxLayout>
00027 #include <QTableWidget>
00028 #include <QComboBox>
00029 #include <QLabel>
00030 #include <QDialogButtonBox>
00031 
00032 #include <iostream>
00033 
00034 #include "base/Debug.h"
00035 
00036 CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format,
00037                                  int maxDisplayCols) :
00038     QDialog(parent),
00039     m_format(format),
00040     m_maxDisplayCols(maxDisplayCols),
00041     m_fuzzyColumn(-1)
00042 {
00043     setModal(true);
00044     setWindowTitle(tr("Select Data Format"));
00045 
00046     QGridLayout *layout = new QGridLayout;
00047 
00048     int row = 0;
00049 
00050     layout->addWidget(new QLabel(tr("Please select the correct data format for this file.")),
00051                       row++, 0, 1, 4);
00052 
00053     QFrame *exampleFrame = new QFrame;
00054     exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00055     exampleFrame->setLineWidth(2);
00056     QGridLayout *exampleLayout = new QGridLayout;
00057     exampleLayout->setSpacing(4);
00058     exampleFrame->setLayout(exampleLayout);
00059 
00060     QPalette palette = exampleFrame->palette();
00061     palette.setColor(QPalette::Window, palette.color(QPalette::Base));
00062     exampleFrame->setPalette(palette);
00063 
00064     QFont fp;
00065     fp.setPointSize(fp.pointSize() * 0.9);
00066 //    fp.setFixedPitch(true);
00067 //    fp.setStyleHint(QFont::TypeWriter);
00068 //    fp.setFamily("Monospaced");
00069     
00070     int columns = format.getColumnCount();
00071     QList<QStringList> example = m_format.getExample();
00072 
00073     for (int i = 0; i < columns; ++i) {
00074 
00075         QComboBox *cpc = new QComboBox;
00076         m_columnPurposeCombos.push_back(cpc);
00077         exampleLayout->addWidget(cpc, 0, i);
00078         connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int)));
00079 
00080         if (i == m_maxDisplayCols && columns > i + 2) {
00081             m_fuzzyColumn = i;
00082             cpc->addItem(tr("<ignore>"));
00083             cpc->addItem(tr("Values"));
00084             cpc->setCurrentIndex
00085                 (m_format.getColumnPurpose(i-1) == CSVFormat::ColumnUnknown ? 0 : 1);
00086             exampleLayout->addWidget(new QLabel(tr("(%1 more)").arg(columns - i)),
00087                                      1, i);
00088             break;
00089         }
00090 
00091         // NB must be in the same order as the CSVFormat::ColumnPurpose enum
00092         cpc->addItem(tr("<ignore>")); // ColumnUnknown
00093         cpc->addItem(tr("Time"));     // ColumnStartTime
00094         cpc->addItem(tr("End time")); // ColumnEndTime
00095         cpc->addItem(tr("Duration")); // ColumnDuration
00096         cpc->addItem(tr("Value"));    // ColumnValue
00097         cpc->addItem(tr("Pitch"));    // ColumnPitch
00098         cpc->addItem(tr("Label"));    // ColumnLabel
00099         cpc->setCurrentIndex(int(m_format.getColumnPurpose(i)));
00100 
00101         for (int j = 0; j < example.size() && j < 6; ++j) {
00102             QLabel *label = new QLabel;
00103             label->setTextFormat(Qt::PlainText);
00104             QString text = TextAbbrev::abbreviate(example[j][i], 35);
00105             label->setText(text);
00106             label->setFont(fp);
00107             label->setPalette(palette);
00108             label->setIndent(8);
00109             exampleLayout->addWidget(label, j+1, i);
00110         }
00111     }
00112 
00113     layout->addWidget(exampleFrame, row, 0, 1, 4);
00114     layout->setColumnStretch(3, 10);
00115     layout->setRowStretch(row++, 10);
00116 
00117     layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
00118     
00119     m_timingTypeCombo = new QComboBox;
00120     m_timingTypeCombo->addItem(tr("Explicitly, in seconds"));
00121     m_timingTypeCombo->addItem(tr("Explicitly, in audio sample frames"));
00122     m_timingTypeCombo->addItem(tr("Implicitly: rows are equally spaced in time"));
00123     layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
00124     connect(m_timingTypeCombo, SIGNAL(activated(int)),
00125             this, SLOT(timingTypeChanged(int)));
00126     m_timingTypeCombo->setCurrentIndex
00127         (m_format.getTimingType() == CSVFormat::ExplicitTiming ?
00128          m_format.getTimeUnits() == CSVFormat::TimeSeconds ? 0 : 1 : 2);
00129 
00130     m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
00131     layout->addWidget(m_sampleRateLabel, row, 0);
00132     
00133     int sampleRates[] = {
00134         8000, 11025, 12000, 22050, 24000, 32000,
00135         44100, 48000, 88200, 96000, 176400, 192000
00136     };
00137 
00138     m_sampleRateCombo = new QComboBox;
00139     for (int i = 0; i < int(sizeof(sampleRates) / sizeof(sampleRates[0])); ++i) {
00140         m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
00141         if (sampleRates[i] == m_format.getSampleRate()) {
00142             m_sampleRateCombo->setCurrentIndex(i);
00143         }
00144     }
00145     m_sampleRateCombo->setEditable(true);
00146 
00147     layout->addWidget(m_sampleRateCombo, row++, 1);
00148     connect(m_sampleRateCombo, SIGNAL(activated(QString)),
00149             this, SLOT(sampleRateChanged(QString)));
00150     connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
00151             this, SLOT(sampleRateChanged(QString)));
00152 
00153     m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
00154     layout->addWidget(m_windowSizeLabel, row, 0);
00155 
00156     m_windowSizeCombo = new QComboBox;
00157     for (int i = 0; i <= 16; ++i) {
00158         int value = 1 << i;
00159         m_windowSizeCombo->addItem(QString("%1").arg(value));
00160         if (value == int(m_format.getWindowSize())) {
00161             m_windowSizeCombo->setCurrentIndex(i);
00162         }
00163     }
00164     m_windowSizeCombo->setEditable(true);
00165 
00166     layout->addWidget(m_windowSizeCombo, row++, 1);
00167     connect(m_windowSizeCombo, SIGNAL(activated(QString)),
00168             this, SLOT(windowSizeChanged(QString)));
00169     connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
00170             this, SLOT(windowSizeChanged(QString)));
00171 
00172     m_modelLabel = new QLabel;
00173     QFont f(m_modelLabel->font());
00174     f.setItalic(true);
00175     m_modelLabel->setFont(f);
00176     layout->addWidget(m_modelLabel, row++, 0, 1, 4);
00177 
00178     QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
00179                                                 QDialogButtonBox::Cancel);
00180     layout->addWidget(bb, row++, 0, 1, 4);
00181     connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
00182     connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
00183 
00184     setLayout(layout);
00185 
00186     timingTypeChanged(m_timingTypeCombo->currentIndex());
00187     updateModelLabel();
00188 }
00189 
00190 CSVFormatDialog::~CSVFormatDialog()
00191 {
00192 }
00193 
00194 CSVFormat
00195 CSVFormatDialog::getFormat() const
00196 {
00197     return m_format;
00198 }
00199 
00200 void
00201 CSVFormatDialog::updateModelLabel()
00202 {
00203     LayerFactory *f = LayerFactory::getInstance();
00204 
00205     QString s;
00206     switch (m_format.getModelType()) {
00207     case CSVFormat::OneDimensionalModel:
00208         s = f->getLayerPresentationName(LayerFactory::TimeInstants);
00209         break;
00210     case CSVFormat::TwoDimensionalModel:
00211         s = f->getLayerPresentationName(LayerFactory::TimeValues);
00212         break; 
00213     case CSVFormat::TwoDimensionalModelWithDuration:
00214         s = f->getLayerPresentationName(LayerFactory::Regions);
00215         break;
00216     case CSVFormat::TwoDimensionalModelWithDurationAndPitch:
00217         s = f->getLayerPresentationName(LayerFactory::Notes);
00218         break;
00219     case CSVFormat::ThreeDimensionalModel:
00220         s = f->getLayerPresentationName(LayerFactory::Colour3DPlot);
00221         break;
00222     }   
00223 
00224     m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.").arg(s));
00225 }
00226 
00227 void
00228 CSVFormatDialog::timingTypeChanged(int type)
00229 {
00230     switch (type) {
00231 
00232     case 0:
00233         m_format.setTimingType(CSVFormat::ExplicitTiming);
00234         m_format.setTimeUnits(CSVFormat::TimeSeconds);
00235         m_sampleRateCombo->setEnabled(false);
00236         m_sampleRateLabel->setEnabled(false);
00237         m_windowSizeCombo->setEnabled(false);
00238         m_windowSizeLabel->setEnabled(false);
00239         break;
00240 
00241     case 1:
00242         m_format.setTimingType(CSVFormat::ExplicitTiming);
00243         m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
00244         m_sampleRateCombo->setEnabled(true);
00245         m_sampleRateLabel->setEnabled(true);
00246         m_windowSizeCombo->setEnabled(false);
00247         m_windowSizeLabel->setEnabled(false);
00248         break;
00249 
00250     case 2:
00251         m_format.setTimingType(CSVFormat::ImplicitTiming);
00252         m_format.setTimeUnits(CSVFormat::TimeWindows);
00253         m_sampleRateCombo->setEnabled(true);
00254         m_sampleRateLabel->setEnabled(true);
00255         m_windowSizeCombo->setEnabled(true);
00256         m_windowSizeLabel->setEnabled(true);
00257         break;
00258     }
00259 }
00260 
00261 void
00262 CSVFormatDialog::sampleRateChanged(QString rateString)
00263 {
00264     bool ok = false;
00265     int sampleRate = rateString.toInt(&ok);
00266     if (ok) m_format.setSampleRate(sampleRate);
00267 }
00268 
00269 void
00270 CSVFormatDialog::windowSizeChanged(QString sizeString)
00271 {
00272     bool ok = false;
00273     int size = sizeString.toInt(&ok);
00274     if (ok) m_format.setWindowSize(size);
00275 }
00276 
00277 void
00278 CSVFormatDialog::columnPurposeChanged(int p)
00279 {
00280     QObject *o = sender();
00281 
00282     QComboBox *cb = qobject_cast<QComboBox *>(o);
00283     if (!cb) return;
00284 
00285     CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p;
00286 
00287     bool haveStartTime = false;
00288     bool haveDuration = false;
00289     bool havePitch = false;
00290     int valueCount = 0;
00291 
00292     for (int i = 0; i < m_columnPurposeCombos.size(); ++i) {
00293 
00294         CSVFormat::ColumnPurpose cp = m_format.getColumnPurpose(i);
00295 
00296         bool thisChanged = (cb == m_columnPurposeCombos[i]);
00297         
00298         if (thisChanged) {
00299 
00300             cerr << "i == " << i << ", fuzzy == " << m_fuzzyColumn
00301                       << ", p == " << p << endl;
00302 
00303             if (i == m_fuzzyColumn) {
00304                 for (int j = i; j < m_format.getColumnCount(); ++j) {
00305                     if (p == 0) { // Ignore
00306                         m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown);
00307                     } else { // Value
00308                         m_format.setColumnPurpose(j, CSVFormat::ColumnValue);
00309                         ++valueCount;
00310                     }
00311                 }
00312                 continue;
00313             }
00314 
00315             cp = purpose;
00316 
00317         } else {
00318 
00319             if (i == m_fuzzyColumn) continue;
00320 
00321             // We can only have one ColumnStartTime column, and only
00322             // one of either ColumnDuration or ColumnEndTime
00323 
00324             if (purpose == CSVFormat::ColumnStartTime) {
00325                 if (cp == purpose) {
00326                     cp = CSVFormat::ColumnValue;
00327                 }
00328             } else if (purpose == CSVFormat::ColumnDuration ||
00329                        purpose == CSVFormat::ColumnEndTime) {
00330                 if (cp == CSVFormat::ColumnDuration ||
00331                     cp == CSVFormat::ColumnEndTime) {
00332                     cp = CSVFormat::ColumnValue;
00333                 }
00334             }
00335 
00336             // And we can only have one label
00337             if (purpose == CSVFormat::ColumnLabel) {
00338                 if (cp == purpose) {
00339                     cp = CSVFormat::ColumnUnknown;
00340                 }
00341             }
00342         }
00343 
00344         if (cp == CSVFormat::ColumnStartTime) {
00345             haveStartTime = true;
00346         }
00347         if (cp == CSVFormat::ColumnEndTime ||
00348             cp == CSVFormat::ColumnDuration) {
00349             haveDuration = true;
00350         }
00351         if (cp == CSVFormat::ColumnPitch) {
00352             havePitch = true;
00353         }
00354         if (cp == CSVFormat::ColumnValue) {
00355             ++valueCount;
00356         }
00357 
00358         m_columnPurposeCombos[i]->setCurrentIndex(int(cp));
00359         m_format.setColumnPurpose(i, cp);
00360     }
00361 
00362     if (!haveStartTime) {
00363         m_timingTypeCombo->setCurrentIndex(2);
00364         timingTypeChanged(2);
00365     }
00366 
00367     if (haveStartTime && haveDuration) {
00368         if (havePitch) {
00369             m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch);
00370         } else {
00371             m_format.setModelType(CSVFormat::TwoDimensionalModelWithDuration);
00372         }
00373     } else {
00374         if (valueCount > 1) {
00375             m_format.setModelType(CSVFormat::ThreeDimensionalModel);
00376         } else if (valueCount > 0) {
00377             m_format.setModelType(CSVFormat::TwoDimensionalModel);
00378         } else {
00379             m_format.setModelType(CSVFormat::OneDimensionalModel);
00380         }
00381     }
00382 
00383     updateModelLabel();
00384 }
00385 
00386