diff --git a/src/ImportCsvDialog.cpp b/src/ImportCsvDialog.cpp index 6a16d8f38..37249eda6 100644 --- a/src/ImportCsvDialog.cpp +++ b/src/ImportCsvDialog.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include ImportCsvDialog::ImportCsvDialog(const QString& filename, DBBrowserDB* db, QWidget* parent) @@ -16,6 +18,13 @@ ImportCsvDialog::ImportCsvDialog(const QString& filename, DBBrowserDB* db, QWidg { ui->setupUi(this); + QStringList encodingList; + foreach(QString enc, QTextCodec::availableCodecs()) + encodingList.push_back(enc); + encodingCompleter = new QCompleter(encodingList, this); + encodingCompleter->setCaseSensitivity(Qt::CaseInsensitive); + ui->editCustomEncoding->setCompleter(encodingCompleter); + checkInput(); updatePreview(); } @@ -42,7 +51,7 @@ void ImportCsvDialog::accept() // Parse all csv data int numfields; - QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), -1, &numfields); + QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), currentEncoding(), -1, &numfields); // Can not operate on an empty result if(numfields == 0) @@ -157,11 +166,12 @@ void ImportCsvDialog::updatePreview() // Show/hide custom quote/separator input fields ui->editCustomQuote->setVisible(ui->comboQuote->currentIndex() == ui->comboQuote->count()-1); ui->editCustomSeparator->setVisible(ui->comboSeparator->currentIndex() == ui->comboSeparator->count()-1); + ui->editCustomEncoding->setVisible(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1); // Get preview data int numfields; int maxrecs = 20; - QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), maxrecs, &numfields); + QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), currentEncoding(), maxrecs, &numfields); // Reset preview widget ui->tablePreview->clear(); @@ -208,7 +218,7 @@ void ImportCsvDialog::checkInput() ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } -char ImportCsvDialog::currentQuoteChar() +char ImportCsvDialog::currentQuoteChar() const { // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead if(ui->comboQuote->currentIndex() == ui->comboQuote->count()-1) @@ -220,7 +230,7 @@ char ImportCsvDialog::currentQuoteChar() return 0; } -char ImportCsvDialog::currentSeparatorChar() +char ImportCsvDialog::currentSeparatorChar() const { // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead if(ui->comboSeparator->currentIndex() == ui->comboSeparator->count()-1) @@ -228,3 +238,12 @@ char ImportCsvDialog::currentSeparatorChar() return ui->comboSeparator->currentText() == tr("Tab") ? '\t' : ui->comboSeparator->currentText().at(0).toLatin1(); } + +QString ImportCsvDialog::currentEncoding() const +{ + // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead + if(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1) + return ui->editCustomEncoding->text().length() ? ui->editCustomEncoding->text() : "UTF-8"; + else + return ui->comboEncoding->currentText(); +} diff --git a/src/ImportCsvDialog.h b/src/ImportCsvDialog.h index bb5e856ea..577cf6fdc 100644 --- a/src/ImportCsvDialog.h +++ b/src/ImportCsvDialog.h @@ -4,6 +4,7 @@ #include class DBBrowserDB; +class QCompleter; namespace Ui { class ImportCsvDialog; @@ -26,9 +27,11 @@ private slots: Ui::ImportCsvDialog* ui; QString csvFilename; DBBrowserDB* pdb; + QCompleter* encodingCompleter; - char currentQuoteChar(); - char currentSeparatorChar(); + char currentQuoteChar() const; + char currentSeparatorChar() const; + QString currentEncoding() const; }; #endif diff --git a/src/ImportCsvDialog.ui b/src/ImportCsvDialog.ui index 9810e4da7..cba14abac 100644 --- a/src/ImportCsvDialog.ui +++ b/src/ImportCsvDialog.ui @@ -170,6 +170,60 @@ + + + + &Encoding + + + comboEncoding + + + + + + + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Other + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -194,8 +248,9 @@ editCustomSeparator comboQuote editCustomQuote + comboEncoding + editCustomEncoding tablePreview - buttonBox @@ -206,8 +261,8 @@ accept() - 252 - 485 + 261 + 480 157 @@ -222,8 +277,8 @@ reject() - 320 - 485 + 329 + 480 286 @@ -327,6 +382,38 @@ + + comboEncoding + currentIndexChanged(int) + ImportCsvDialog + updatePreview() + + + 198 + 131 + + + 572 + 121 + + + + + editCustomEncoding + textChanged(QString) + ImportCsvDialog + updatePreview() + + + 378 + 132 + + + 540 + 133 + + + updatePreview() diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 279f3fb75..aaac7553d 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -873,7 +873,7 @@ void DBBrowserDB::updateSchema( ) } } -QStringList DBBrowserDB::decodeCSV(const QString & csvfilename, char sep, char quote, int maxrecords, int * numfields) +QStringList DBBrowserDB::decodeCSV(const QString & csvfilename, char sep, char quote, const QString& encoding, int maxrecords, int * numfields) { QFile file(csvfilename); QStringList result; @@ -886,6 +886,7 @@ QStringList DBBrowserDB::decodeCSV(const QString & csvfilename, char sep, char q //Other than QFile, the QTextStream-class properly detects 2-Byte QChars and converts them accordingly (UTF-8) QTextStream inStream(&file); + inStream.setCodec(encoding.toUtf8()); QProgressDialog progress(QObject::tr("Decoding CSV file..."), QObject::tr("Cancel"), 0, file.size()); progress.setWindowModality(Qt::ApplicationModal); diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 11cdcf920..18401143c 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -110,7 +110,7 @@ class DBBrowserDB : public QObject sqlite3 * _db; - QStringList decodeCSV(const QString & csvfilename, char sep, char quote, int maxrecords, int * numfields); + QStringList decodeCSV(const QString & csvfilename, char sep, char quote, const QString& encoding, int maxrecords, int * numfields); objectMap objMap; diff --git a/src/tests/TestImport.cpp b/src/tests/TestImport.cpp index b35e02f64..e3d3c9ad4 100644 --- a/src/tests/TestImport.cpp +++ b/src/tests/TestImport.cpp @@ -11,6 +11,7 @@ void TestImport::csvImport() QFETCH(QString, csv); QFETCH(char, separator); QFETCH(char, quote); + QFETCH(QString, encoding); QFETCH(int, numfields); QFETCH(QStringList, result); @@ -28,7 +29,7 @@ void TestImport::csvImport() // Call decodeCSV function DBBrowserDB db; int numfields_read; - QStringList retval = db.decodeCSV(file.fileName(), separator, quote, -1, &numfields_read); + QStringList retval = db.decodeCSV(file.fileName(), separator, quote, encoding, -1, &numfields_read); // Check return values QCOMPARE(retval, result); @@ -40,6 +41,7 @@ void TestImport::csvImport_data() QTest::addColumn("csv"); QTest::addColumn("separator"); QTest::addColumn("quote"); + QTest::addColumn("encoding"); QTest::addColumn("numfields"); QTest::addColumn("result"); @@ -48,26 +50,31 @@ void TestImport::csvImport_data() QTest::newRow("commas_noquotes") << "a,b,c\nd,e,f\ng,h,i\n" << ',' << (char)0 + << "UTF-8" << 3 << result; QTest::newRow("semicolons_noquotes") << "a;b;c\nd;e;f\ng;h;i\n" << ';' << (char)0 + << "UTF-8" << 3 << result; QTest::newRow("commas_doublequotes") << "\"a\",\"b\",\"c\"\n\"d\",\"e\",\"f\"\n\"g\",\"h\",\"i\"\n" << ',' << '"' + << "UTF-8" << 3 << result; QTest::newRow("noquotes_butquotesset") << "a,b,c\nd,e,f\ng,h,i\n" << ',' << '"' + << "UTF-8" << 3 << result; QTest::newRow("windowslinebreaks") << "a,b,c\r\nd,e,f\r\ng,h,i\r\n" << ',' << (char)0 + << "UTF-8" << 3 << result; @@ -76,6 +83,7 @@ void TestImport::csvImport_data() QTest::newRow("oneline") << "a,b,c" << ',' << (char)0 + << "UTF-8" << 3 << result; @@ -84,6 +92,7 @@ void TestImport::csvImport_data() QTest::newRow("manyquotes") << "\"a,a\"\"\",\"b\",\"c\"\n\"d\",\"e\",\"\"\"\"\"f,f\"\n" << ',' << '"' + << "UTF-8" << 3 << result; @@ -93,6 +102,7 @@ void TestImport::csvImport_data() QTest::newRow("utf8chars") << csv << ',' << (char)0 + << "UTF-8" << 3 << result; }