Version: 1.5 (using KDE KDE 3.5.4) Installed from: Compiled From Sources Not only can't you simply save (Ctrl+S) a csv file with the same settings as it was opened with in the first place without getting the dialog, the dialog even does *not remember* the latest settings. I. e. I load a csv file with latin1 encoding, change it and save it (Ctrl+S). Then I get the export dialog, having "UTF-8" preselected. I click onto the text (which is easier to reach than the tiny knob at the far side), only to have a *caret* placed into the combo box line instead of popping up the menu. Then I click the knob, select latin1 and click OK. I have to perform these steps *every single time* I want to save a csv-file. This is *even nastier* than excel which only bugs about potential loss of formatting, but doesn't force to to change settings all time.
SVN commit 623416 by savernik: Fix nasty bugs and usability issues of csv-converter: - Remember settings. - Don't convert already converted document to utf8. - Don't ignore newline settings on export (and only export unix-nl). BUG: 132462 M +44 -1 csvdialog.cpp M +2 -0 csvdialog.h M +27 -6 csvexport.cc M +1 -1 csvexport.h M +53 -0 csvexportdialog.cpp M +2 -0 csvexportdialog.h M +1 -1 csvimport.cc --- branches/koffice/1.6/koffice/filters/kspread/csv/csvdialog.cpp #623415:623416 @@ -34,6 +34,7 @@ #include <qtextcodec.h> #include <kapplication.h> +#include <kconfig.h> #include <kdebug.h> #include <klocale.h> #include <kcombobox.h> @@ -57,7 +58,7 @@ { setCaption( i18n( "Import" ) ); kapp->restoreOverrideCursor(); - + QStringList encodings; encodings << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" ); encodings << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->name() ); @@ -79,6 +80,8 @@ m_dialog->m_sheet->setReadOnly( true ); + loadSettings(); + fillTable(); //resize(sizeHint()); @@ -109,9 +112,49 @@ CSVDialog::~CSVDialog() { + saveSettings(); kapp->setOverrideCursor(Qt::waitCursor); } +void CSVDialog::loadSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("CSVDialog Settings"); + m_textquote = config->readEntry("textquote", "\"")[0]; + m_delimiter = config->readEntry("delimiter", ","); + m_ignoreDups = config->readBoolEntry("ignoreDups", false); + const QString codecText = config->readEntry("codec", ""); + + // update widgets + if (!codecText.isEmpty()) { + m_dialog->comboBoxEncoding->setCurrentText(codecText); + m_codec = getCodec(); + } + if (m_delimiter == ",") m_dialog->m_radioComma->setChecked(true); + else if (m_delimiter == "\t") m_dialog->m_radioTab->setChecked(true); + else if (m_delimiter == " ") m_dialog->m_radioSpace->setChecked(true); + else if (m_delimiter == ";") m_dialog->m_radioSemicolon->setChecked(true); + else { + m_dialog->m_radioOther->setChecked(true); + m_dialog->m_delimiterEdit->setText(m_delimiter); + } + m_dialog->m_ignoreDuplicates->setChecked(m_ignoreDups); + m_dialog->m_comboQuote->setCurrentItem(m_textquote == '\'' ? 1 + : m_textquote == '"' ? 0 : 2); +} + +void CSVDialog::saveSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("CSVDialog Settings"); + QString q = m_textquote; + config->writeEntry("textquote", q); + config->writeEntry("delimiter", m_delimiter); + config->writeEntry("ignoreDups", m_ignoreDups); + config->writeEntry("codec", m_dialog->comboBoxEncoding->currentText()); + config->sync(); +} + void CSVDialog::fillTable( ) { int row, column; --- branches/koffice/1.6/koffice/filters/kspread/csv/csvdialog.h #623415:623416 @@ -50,6 +50,8 @@ QString getText(int row, int col); private: + void loadSettings(); + void saveSettings(); void fillTable(); void fillComboBox(); void setText(int row, int col, const QString& text); --- branches/koffice/1.6/koffice/filters/kspread/csv/csvexport.cc #623415:623416 @@ -64,7 +64,7 @@ { } -QString CSVExport::exportCSVCell( Sheet const * const sheet, int col, int row, QChar const & textQuote ) +QString CSVExport::exportCSVCell( Sheet const * const sheet, int col, int row, QChar const & textQuote, QChar csvDelimiter ) { // This function, given a cell, returns a string corresponding to its export in CSV format // It proceeds by: @@ -89,6 +89,8 @@ text = cell->strOutText(); } + // quote only when needed (try to mimic excel) + bool quote = false; if ( !text.isEmpty() ) { if ( text.find( textQuote ) != -1 ) @@ -96,8 +98,17 @@ QString doubleTextQuote(textQuote); doubleTextQuote.append(textQuote); text.replace(textQuote, doubleTextQuote); - } + quote = true; + } else if ( text[0].isSpace() || text[text.length()-1].isSpace() ) + quote = true; + else if ( text.find( csvDelimiter ) != -1 ) + quote = true; + else if ( text.find( "\n" ) != -1 || text.find( "\r" ) != -1 ) + quote = true; + } + + if ( quote ) { text.prepend(textQuote); text.append(textQuote); } @@ -164,6 +175,7 @@ return KoFilter::StupidError; } csvDelimiter = expDialog->getDelimiter(); + m_eol = expDialog->getEndOfLine(); } else { @@ -229,7 +241,7 @@ for ( int col = selection.left(); col <= right && idxCol <= CSVMaxCol; ++col, ++idxCol ) { - str += exportCSVCell( sheet, col, row, textQuote ); + str += exportCSVCell( sheet, col, row, textQuote, csvDelimiter ); if ( idxCol < CSVMaxCol ) str += csvDelimiter; @@ -324,13 +336,22 @@ i = 0; } + QString collect; // buffer delimiters while reading empty cells + for ( int col = 1 ; col <= CSVMaxCol ; col++ ) { - str += exportCSVCell( sheet, col, row, textQuote ); + const QString txt = exportCSVCell( sheet, col, row, textQuote, csvDelimiter ); - if ( col < CSVMaxCol ) - str += csvDelimiter; + // if we encounter a non-empty cell, commit the buffered delimiters + if (!txt.isEmpty()) { + str += collect + txt; + collect = QString(); + } + + collect += csvDelimiter; } + // Here, throw away buffered delimiters. They're trailing and therefore + // superfluous. str += m_eol; } --- branches/koffice/1.6/koffice/filters/kspread/csv/csvexport.h #623415:623416 @@ -40,7 +40,7 @@ virtual KoFilter::ConversionStatus convert( const QCString & from, const QCString & to ); private: - QString exportCSVCell( KSpread::Sheet const * const sheet, int col, int row, QChar const & textQuote ); + QString exportCSVCell( KSpread::Sheet const * const sheet, int col, int row, QChar const & textQuote, QChar delimiter ); private: QString m_eol; ///< End of line (LF, CR or CRLF) --- branches/koffice/1.6/koffice/filters/kspread/csv/csvexportdialog.cpp #623415:623416 @@ -39,6 +39,7 @@ #include <qvalidator.h> #include <kapplication.h> +#include <kconfig.h> #include <klocale.h> #include <kdebug.h> #include <kcombobox.h> @@ -88,14 +89,66 @@ this, SLOT( textquoteSelected( const QString & ) ) ); connect( m_dialog->m_selectionOnly, SIGNAL( toggled( bool ) ), this, SLOT( selectionOnlyChanged( bool ) ) ); + + loadSettings(); } CSVExportDialog::~CSVExportDialog() { + saveSettings(); kapp->setOverrideCursor(Qt::waitCursor); delete m_delimiterValidator; } +void CSVExportDialog::loadSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("CSVDialog Settings"); + m_textquote = config->readEntry("textquote", "\"")[0]; + m_delimiter = config->readEntry("delimiter", ","); + const QString codecText = config->readEntry("codec", ""); + bool selectionOnly = config->readBoolEntry("selectionOnly", false); + const QString sheetDelim = config->readEntry("sheetDelimiter", m_dialog->m_sheetDelimiter->text()); + bool delimAbove = config->readBoolEntry("sheetDelimiterAbove", false); + const QString eol = config->readEntry("eol", "\r\n"); + + // update widgets + if (!codecText.isEmpty()) { + m_dialog->comboBoxEncoding->setCurrentText(codecText); + } + if (m_delimiter == ",") m_dialog->m_radioComma->setChecked(true); + else if (m_delimiter == "\t") m_dialog->m_radioTab->setChecked(true); + else if (m_delimiter == " ") m_dialog->m_radioSpace->setChecked(true); + else if (m_delimiter == ";") m_dialog->m_radioSemicolon->setChecked(true); + else { + m_dialog->m_radioOther->setChecked(true); + m_dialog->m_delimiterEdit->setText(m_delimiter); + } + m_dialog->m_comboQuote->setCurrentItem(m_textquote == '\'' ? 1 + : m_textquote == '"' ? 0 : 2); + m_dialog->m_selectionOnly->setChecked(selectionOnly); + m_dialog->m_sheetDelimiter->setText(sheetDelim); + m_dialog->m_delimiterAboveAll->setChecked(delimAbove); + if (eol == "\r\n") m_dialog->radioEndOfLineCRLF->setChecked(true); + else if (eol == "\r") m_dialog->radioEndOfLineCR->setChecked(true); + else m_dialog->radioEndOfLineLF->setChecked(true); +} + +void CSVExportDialog::saveSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("CSVDialog Settings"); + QString q = m_textquote; + config->writeEntry("textquote", q); + config->writeEntry("delimiter", m_delimiter); + config->writeEntry("codec", m_dialog->comboBoxEncoding->currentText()); + config->writeEntry("selectionOnly", exportSelectionOnly()); + config->writeEntry("sheetDelimiter", getSheetDelimiter()); + config->writeEntry("sheetDelimiterAbove", printAlwaysSheetDelimiter()); + config->writeEntry("eol", getEndOfLine()); + config->sync(); +} + void CSVExportDialog::fillSheet( Map * map ) { m_dialog->m_sheetList->clear(); --- branches/koffice/1.6/koffice/filters/kspread/csv/csvexportdialog.h #623415:623416 @@ -50,6 +50,8 @@ QTextCodec* getCodec(void) const; private: + void loadSettings(); + void saveSettings(); ExportDialogUI * m_dialog; QValidator* m_delimiterValidator; --- branches/koffice/1.6/koffice/filters/kspread/csv/csvimport.cc #623415:623416 @@ -142,7 +142,7 @@ { value += step; emit sigProgress(value); - const QString text( dialog->getText( row, col ).utf8() ); + const QString text( dialog->getText( row, col ) ); // ### FIXME: how to calculate the width of numbers (as they might not be in the right format) const double len = fm.width( text );