Warning, file /office/calligra/libs/widgets/KoCsvImportDialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 1999 David Faure <faure@kde.org>
0003    Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KoCsvImportDialog.h"
0022 
0023 // Qt
0024 #include <QButtonGroup>
0025 #include <QTextCodec>
0026 #include <QTextStream>
0027 
0028 #include <QTableWidget>
0029 #include <QTableWidgetSelectionRange>
0030 
0031 // KF5
0032 #include <kcharsets.h>
0033 #include <kconfig.h>
0034 #include <WidgetsDebug.h>
0035 #include <klocalizedstring.h>
0036 #include <kmessagebox.h>
0037 #include <ksharedconfig.h>
0038 
0039 #include "ui_KoCsvImportDialog.h"
0040 
0041 class KoCsvImportWidget : public QWidget, public Ui::KoCsvImportWidget
0042 {
0043 Q_OBJECT
0044 public:
0045     explicit KoCsvImportWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
0046 };
0047 
0048 
0049 class Q_DECL_HIDDEN KoCsvImportDialog::Private
0050 {
0051 public:
0052     KoCsvImportDialog* q;
0053     KoCsvImportWidget* dialog;
0054 
0055     bool        rowsAdjusted;
0056     bool        columnsAdjusted;
0057     int         startRow;
0058     int         startCol;
0059     int         endRow;
0060     int         endCol;
0061     QChar       textQuote;
0062     QString     delimiter;
0063     QString     commentSymbol;
0064     bool        ignoreDuplicates;
0065     QByteArray  data;
0066     QTextCodec* codec;
0067     QStringList formatList; ///< List of the column formats
0068 
0069     explicit Private(KoCsvImportDialog* qq) : q(qq) {}
0070     void loadSettings();
0071     void saveSettings();
0072     void fillTable();
0073     void setText(int row, int col, const QString& text);
0074     void adjustRows(int iRows);
0075     void adjustCols(int iCols);
0076     bool checkUpdateRange();
0077     QTextCodec* updateCodec() const;
0078 };
0079 
0080 KoCsvImportDialog::KoCsvImportDialog(QWidget* parent)
0081     : KoDialog(parent)
0082     , d(new Private(this))
0083 {
0084     d->dialog = new KoCsvImportWidget(this);
0085     d->rowsAdjusted = false;
0086     d->columnsAdjusted = false;
0087     d->startRow = 0;
0088     d->startCol = 0;
0089     d->endRow = -1;
0090     d->endCol = -1;
0091     d->textQuote = QChar('"');
0092     d->delimiter = QString(',');
0093     d->commentSymbol = QString('#');
0094     d->ignoreDuplicates = false;
0095     d->codec = QTextCodec::codecForName("UTF-8");
0096 
0097     setButtons( KoDialog::Ok|KoDialog::Cancel );
0098     setCaption( i18n( "Import Data" ) );
0099 
0100     QStringList encodings;
0101     encodings << i18nc( "Descriptive encoding name", "Recommended ( %1 )" ,"UTF-8" );
0102     encodings << i18nc( "Descriptive encoding name", "Locale ( %1 )" ,QString(QTextCodec::codecForLocale()->name() ));
0103     encodings += KCharsets::charsets()->descriptiveEncodingNames();
0104     // Add a few non-standard encodings, which might be useful for text files
0105     const QString description(i18nc("Descriptive encoding name","Other ( %1 )"));
0106     encodings << description.arg("Apple Roman"); // Apple
0107     encodings << description.arg("IBM 850") << description.arg("IBM 866"); // MS DOS
0108     encodings << description.arg("CP 1258"); // Windows
0109     d->dialog->comboBoxEncoding->insertItems( 0, encodings );
0110 
0111     setDataTypes(Generic|Text|Date|None);
0112  
0113     // XXX: Qt3->Q4
0114     //d->dialog->m_sheet->setReadOnly( true );
0115 
0116     d->loadSettings();
0117 
0118     //resize(sizeHint());
0119     resize( 600, 400 ); // Try to show as much as possible of the table view
0120     setMainWidget(d->dialog);
0121 
0122     d->dialog->m_sheet->setSelectionMode( QAbstractItemView::MultiSelection );
0123 
0124     QButtonGroup* buttonGroup = new QButtonGroup( this );
0125     buttonGroup->addButton(d->dialog->m_radioComma, 0);
0126     buttonGroup->addButton(d->dialog->m_radioSemicolon, 1);
0127     buttonGroup->addButton(d->dialog->m_radioSpace, 2);
0128     buttonGroup->addButton(d->dialog->m_radioTab, 3);
0129     buttonGroup->addButton(d->dialog->m_radioOther, 4);
0130 
0131     connect(d->dialog->m_formatComboBox, SIGNAL(activated(QString)),
0132             this, SLOT(formatChanged(QString)));
0133     connect(buttonGroup, SIGNAL(buttonClicked(int)),
0134             this, SLOT(delimiterClicked(int)));
0135     connect(d->dialog->m_delimiterEdit, SIGNAL(returnPressed()),
0136             this, SLOT(returnPressed()));
0137     connect(d->dialog->m_delimiterEdit, SIGNAL(textChanged(QString)),
0138             this, SLOT(genericDelimiterChanged(QString)));
0139     connect(d->dialog->m_comboQuote, SIGNAL(activated(QString)),
0140             this, SLOT(textquoteSelected(QString)));
0141     connect(d->dialog->m_sheet, SIGNAL(currentCellChanged(int,int,int,int)),
0142             this, SLOT(currentCellChanged(int,int)));
0143     connect(d->dialog->m_ignoreDuplicates, SIGNAL(stateChanged(int)),
0144             this, SLOT(ignoreDuplicatesChanged(int)));
0145     connect(d->dialog->m_updateButton, SIGNAL(clicked()),
0146             this, SLOT(updateClicked()));
0147     connect(d->dialog->comboBoxEncoding, SIGNAL(textChanged(QString)),
0148             this, SLOT(encodingChanged(QString)));
0149 }
0150 
0151 
0152 KoCsvImportDialog::~KoCsvImportDialog()
0153 {
0154     d->saveSettings();
0155     delete d;
0156 }
0157 
0158 
0159 // ----------------------------------------------------------------
0160 //                       public methods
0161 
0162 
0163 void KoCsvImportDialog::setData( const QByteArray& data )
0164 {
0165     d->data = data;
0166     d->fillTable();
0167 }
0168 
0169 
0170 bool KoCsvImportDialog::firstRowContainHeaders() const
0171 {
0172     return d->dialog->m_firstRowHeader->isChecked();
0173 }
0174 
0175 
0176 bool KoCsvImportDialog::firstColContainHeaders() const
0177 {
0178     return d->dialog->m_firstColHeader->isChecked();
0179 }
0180 
0181 
0182 int KoCsvImportDialog::rows() const
0183 {
0184     int rows = d->dialog->m_sheet->rowCount();
0185 
0186     if ( d->endRow >= 0 )
0187     rows = d->endRow - d->startRow + 1;
0188 
0189     return rows;
0190 }
0191 
0192 
0193 int KoCsvImportDialog::cols() const
0194 {
0195     int cols = d->dialog->m_sheet->columnCount();
0196 
0197     if ( d->endCol >= 0 )
0198     cols = d->endCol - d->startCol + 1;
0199 
0200     return cols;
0201 }
0202 
0203 
0204 QString KoCsvImportDialog::text(int row, int col) const
0205 {
0206     // Check for overflow.
0207     if ( row >= rows() || col >= cols())
0208         return QString();
0209 
0210     QTableWidgetItem* item = d->dialog->m_sheet->item( row - d->startRow, col - d->startCol );
0211     if ( !item )
0212         return QString();
0213     return item->text();
0214 }
0215 
0216 void KoCsvImportDialog::setDataTypes(DataTypes dataTypes)
0217 {
0218     d->formatList.clear();
0219     if (dataTypes & Generic)
0220         d->formatList << i18n("Generic");
0221     if (dataTypes & Text)
0222         d->formatList << i18n("Text");
0223     if (dataTypes & Date)
0224         d->formatList << i18n("Date");
0225     if (dataTypes & Currency)
0226         d->formatList << i18n("Currency");
0227     if (dataTypes & None)
0228         d->formatList << i18n("None");
0229     d->dialog->m_formatComboBox->insertItems(0, d->formatList);
0230 }
0231 
0232 void KoCsvImportDialog::setDataWidgetEnabled(bool enable)
0233 {
0234     d->dialog->m_tabWidget->setTabEnabled(0, enable);
0235 }
0236 
0237 QString KoCsvImportDialog::decimalSymbol() const
0238 {
0239     return d->dialog->m_decimalSymbol->text();
0240 }
0241 
0242 void KoCsvImportDialog::setDecimalSymbol(const QString& symbol)
0243 {
0244     d->dialog->m_decimalSymbol->setText(symbol);
0245 }
0246 
0247 QString KoCsvImportDialog::thousandsSeparator() const
0248 {
0249     return d->dialog->m_thousandsSeparator->text();
0250 }
0251 
0252 void KoCsvImportDialog::setThousandsSeparator(const QString& separator)
0253 {
0254     d->dialog->m_thousandsSeparator->setText(separator);
0255 }
0256 
0257 QString KoCsvImportDialog::delimiter() const
0258 {
0259     return d->delimiter;
0260 }
0261 
0262 void KoCsvImportDialog::setDelimiter(const QString& delimit)
0263 {
0264     d->delimiter = delimit;
0265     if (delimit == ",")
0266         d->dialog->m_radioComma->setChecked(true);
0267     else if (delimit == "\t")
0268         d->dialog->m_radioTab->setChecked(true);
0269     else if (delimit == " ")
0270         d->dialog->m_radioSpace->setChecked(true);
0271     else if (delimit == ";")
0272         d->dialog->m_radioSemicolon->setChecked(true);
0273     else {
0274         d->dialog->m_radioOther->setChecked(true);
0275         d->dialog->m_delimiterEdit->setText(delimit);
0276     }
0277 }
0278 
0279 
0280 // ----------------------------------------------------------------
0281 
0282 
0283 void KoCsvImportDialog::Private::loadSettings()
0284 {
0285     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("CSVDialog Settings");
0286     textQuote = configGroup.readEntry("textQuote", "\"").at(0);
0287     delimiter = configGroup.readEntry("delimiter", ",");
0288     ignoreDuplicates = configGroup.readEntry("ignoreDups", false);
0289     const QString codecText = configGroup.readEntry("codec", "");
0290 
0291     // update widgets
0292     if (!codecText.isEmpty()) {
0293       dialog->comboBoxEncoding->setCurrentIndex(dialog->comboBoxEncoding->findText(codecText));
0294       codec = updateCodec();
0295     }
0296     q->setDelimiter(delimiter);
0297     dialog->m_ignoreDuplicates->setChecked(ignoreDuplicates);
0298     dialog->m_comboQuote->setCurrentIndex(textQuote == '\'' ? 1 : textQuote == '"' ? 0 : 2);
0299 }
0300 
0301 void KoCsvImportDialog::Private::saveSettings()
0302 {
0303     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("CSVDialog Settings");
0304     configGroup.writeEntry("textQuote", QString(textQuote));
0305     configGroup.writeEntry("delimiter", delimiter);
0306     configGroup.writeEntry("ignoreDups", ignoreDuplicates);
0307     configGroup.writeEntry("codec", dialog->comboBoxEncoding->currentText());
0308     configGroup.sync();
0309 }
0310 
0311 void KoCsvImportDialog::Private::fillTable()
0312 {
0313     int row, column;
0314     bool lastCharDelimiter = false;
0315     enum { Start, InQuotedField, MaybeQuotedFieldEnd, QuotedFieldEnd,
0316            MaybeInNormalField, InNormalField } state = Start;
0317 
0318     QChar x;
0319     QString field;
0320 
0321     QApplication::setOverrideCursor(Qt::WaitCursor);
0322 
0323     dialog->m_sheet->setRowCount(0);
0324     dialog->m_sheet->setColumnCount(0);
0325 
0326     int maxColumn = 1;
0327     row = column = 1;
0328     QTextStream inputStream(data, QIODevice::ReadOnly);
0329     debugWidgets <<"Encoding:" << codec->name();
0330     inputStream.setCodec( codec );
0331 
0332     int delimiterIndex = 0;
0333     const int delimiterLength = delimiter.size();
0334     bool lastCharWasCr = false; // Last character was a Carriage Return
0335     while (!inputStream.atEnd())
0336     {
0337         inputStream >> x; // read one char
0338 
0339         // ### TODO: we should perhaps skip all other control characters
0340         if ( x == '\r' )
0341         {
0342             // We have a Carriage Return, assume that its role is the one of a LineFeed
0343             lastCharWasCr = true;
0344             x = '\n'; // Replace by Line Feed
0345         }
0346         else if ( x == '\n' && lastCharWasCr )
0347         {
0348             // The end of line was already handled by the Carriage Return, so do nothing for this character
0349             lastCharWasCr = false;
0350             continue;
0351         }
0352         else if ( x == QChar( 0xc ) )
0353         {
0354             // We have a FormFeed, skip it
0355             lastCharWasCr = false;
0356             continue;
0357         }
0358         else
0359         {
0360             lastCharWasCr = false;
0361         }
0362 
0363         if ( column > maxColumn )
0364           maxColumn = column;
0365         switch (state)
0366         {
0367          case Start :
0368             if (x == textQuote)
0369             {
0370                 state = InQuotedField;
0371             }
0372             else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
0373             {
0374                 field += x;
0375                 delimiterIndex++;
0376                 if (field.right(delimiterIndex) == delimiter)
0377                 {
0378                     if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
0379                         column += delimiterLength;
0380                     lastCharDelimiter = true;
0381                     field.clear();
0382                     delimiterIndex = 0;
0383                     state = Start;
0384                 }
0385                 else if (delimiterIndex >= delimiterLength)
0386                     delimiterIndex = 0;
0387             }
0388             else if (x == '\n')
0389             {
0390                 ++row;
0391                 column = 1;
0392                 if ( row > ( endRow - startRow ) && endRow >= 0 )
0393                   break;
0394             }
0395             else
0396             {
0397                 field += x;
0398                 state = MaybeInNormalField;
0399             }
0400             break;
0401          case InQuotedField :
0402             if (x == textQuote)
0403             {
0404                 state = MaybeQuotedFieldEnd;
0405             }
0406             else if (x == '\n')
0407             {
0408                 setText(row - startRow, column - startCol, field);
0409                 field.clear();
0410 
0411                 ++row;
0412                 column = 1;
0413                 if ( row > ( endRow - startRow ) && endRow >= 0 )
0414                   break;
0415 
0416                 state = Start;
0417             }
0418             else
0419             {
0420                 field += x;
0421             }
0422             break;
0423          case MaybeQuotedFieldEnd :
0424             if (x == textQuote)
0425             {
0426                 field += x;
0427                 state = InQuotedField;
0428             }
0429             else if (x == '\n')
0430             {
0431                 setText(row - startRow, column - startCol, field);
0432                 field.clear();
0433                 ++row;
0434                 column = 1;
0435                 if ( row > ( endRow - startRow ) && endRow >= 0 )
0436                     break;
0437                 state = Start;
0438             }
0439             else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
0440             {
0441                 field += x;
0442                 delimiterIndex++;
0443                 if (field.right(delimiterIndex) == delimiter)
0444                 {
0445                     setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
0446                     field.clear();
0447                     if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
0448                         column += delimiterLength;
0449                     lastCharDelimiter = true;
0450                     field.clear();
0451                     delimiterIndex = 0;
0452                 }
0453                 else if (delimiterIndex >= delimiterLength)
0454                     delimiterIndex = 0;
0455                 state = Start;
0456             }
0457             else
0458             {
0459                 state = QuotedFieldEnd;
0460             }
0461             break;
0462          case QuotedFieldEnd :
0463             if (x == '\n')
0464             {
0465                 setText(row - startRow, column - startCol, field);
0466                 field.clear();
0467                 ++row;
0468                 column = 1;
0469                 if ( row > ( endRow - startRow ) && endRow >= 0 )
0470                     break;
0471                 state = Start;
0472             }
0473             else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
0474             {
0475                 field += x;
0476                 delimiterIndex++;
0477                 if (field.right(delimiterIndex) == delimiter)
0478                 {
0479                     setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
0480                     field.clear();
0481                     if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
0482                         column += delimiterLength;
0483                     lastCharDelimiter = true;
0484                     field.clear();
0485                     delimiterIndex = 0;
0486                 }
0487                 else if (delimiterIndex >= delimiterLength)
0488                     delimiterIndex = 0;
0489                 state = Start;
0490             }
0491             else
0492             {
0493                 state = QuotedFieldEnd;
0494             }
0495             break;
0496          case MaybeInNormalField :
0497             if (x == textQuote)
0498             {
0499                 field.clear();
0500                 state = InQuotedField;
0501                 break;
0502             }
0503             state = InNormalField;
0504          case InNormalField :
0505             if (x == '\n')
0506             {
0507                 setText(row - startRow, column - startCol, field);
0508                 field.clear();
0509                 ++row;
0510                 column = 1;
0511                 if ( row > ( endRow - startRow ) && endRow >= 0 )
0512                     break;
0513                 state = Start;
0514             }
0515             else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
0516             {
0517                 field += x;
0518                 delimiterIndex++;
0519                 if (field.right(delimiterIndex) == delimiter)
0520                 {
0521                     setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
0522                     field.clear();
0523                     if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
0524                         column += delimiterLength;
0525                     lastCharDelimiter = true;
0526                     field.clear();
0527                     delimiterIndex = 0;
0528                 }
0529                 else if (delimiterIndex >= delimiterLength)
0530                     delimiterIndex = 0;
0531                 state = Start;
0532             }
0533             else
0534             {
0535                 field += x;
0536             }
0537         }
0538         if (delimiter.isEmpty() || x != delimiter.at(0))
0539           lastCharDelimiter = false;
0540     }
0541 
0542     if ( !field.isEmpty() )
0543     {
0544       // the last line of the file had not any line end
0545       setText(row - startRow, column - startCol, field);
0546       ++row;
0547       field.clear();
0548     }
0549     if (row) row--;  // row is higher by 1, so reduce it
0550 
0551     columnsAdjusted = true;
0552     adjustRows( row - startRow );
0553     adjustCols( maxColumn - startCol );
0554 
0555     for (column = 0; column < dialog->m_sheet->columnCount(); ++column)
0556     {
0557         const QTableWidgetItem* headerItem = dialog->m_sheet->horizontalHeaderItem(column);
0558         if (!headerItem || !formatList.contains(headerItem->text())) {
0559             dialog->m_sheet->setHorizontalHeaderItem(column, new QTableWidgetItem(i18n("Generic")));
0560         }
0561     }
0562 
0563     dialog->m_rowStart->setMinimum(1);
0564     dialog->m_colStart->setMinimum(1);
0565     dialog->m_rowStart->setMaximum(row);
0566     dialog->m_colStart->setMaximum(maxColumn);
0567 
0568     dialog->m_rowEnd->setMinimum(1);
0569     dialog->m_colEnd->setMinimum(1);
0570     dialog->m_rowEnd->setMaximum(row);
0571     dialog->m_colEnd->setMaximum(maxColumn);
0572     dialog->m_rowEnd->setValue(endRow == -1 ? row : endRow);
0573     dialog->m_colEnd->setValue(endCol == -1 ? maxColumn : endCol);
0574 
0575     QApplication::restoreOverrideCursor();
0576 }
0577 
0578 KoCsvImportDialog::DataType KoCsvImportDialog::dataType(int col) const
0579 {
0580     const QString header = d->dialog->m_sheet->model()->headerData(col, Qt::Horizontal).toString();
0581 
0582     if (header == i18n("Generic"))
0583         return Generic;
0584     else if (header == i18n("Text"))
0585         return Text;
0586     else if (header == i18n("Date"))
0587         return Date;
0588     else if (header == i18n("Currency"))
0589         return Currency;
0590     else if (header == i18n("None"))
0591         return None;
0592     return Generic;
0593 }
0594 
0595 void KoCsvImportDialog::Private::setText(int row, int col, const QString& text)
0596 {
0597     if (row < 1 || col < 1) // skipped by the user
0598         return;
0599 
0600     if ((row > (endRow - startRow) && endRow > 0) || (col > (endCol - startCol) && endCol > 0))
0601       return;
0602 
0603     if (dialog->m_sheet->rowCount() < row)
0604     {
0605         dialog->m_sheet->setRowCount(row + 5000); /* We add 5000 at a time to limit recalculations */
0606         rowsAdjusted = true;
0607     }
0608 
0609     if (dialog->m_sheet->columnCount() < col)
0610     {
0611         dialog->m_sheet->setColumnCount(col);
0612         columnsAdjusted = true;
0613     }
0614 
0615     QTableWidgetItem* item = dialog->m_sheet->item(row - 1, col - 1);
0616     if (!item) {
0617         item = new QTableWidgetItem();
0618         dialog->m_sheet->setItem(row - 1, col - 1, item);
0619     }
0620     item->setText(text);
0621 }
0622 
0623 /*
0624  * Called after the first fillTable() when number of rows are unknown.
0625  */
0626 void KoCsvImportDialog::Private::adjustRows(int iRows)
0627 {
0628     if (rowsAdjusted)
0629     {
0630         dialog->m_sheet->setRowCount(iRows);
0631         rowsAdjusted = false;
0632     }
0633 }
0634 
0635 void KoCsvImportDialog::Private::adjustCols(int iCols)
0636 {
0637     if (columnsAdjusted)
0638     {
0639         dialog->m_sheet->setColumnCount(iCols);
0640         columnsAdjusted = false;
0641 
0642         if (endCol == -1)
0643         {
0644           if (iCols > (endCol - startCol))
0645             iCols = endCol - startCol;
0646 
0647           dialog->m_sheet->setColumnCount(iCols);
0648         }
0649     }
0650 }
0651 
0652 void KoCsvImportDialog::returnPressed()
0653 {
0654     if (d->dialog->m_radioOther->isChecked())
0655         return;
0656 
0657     d->delimiter = d->dialog->m_delimiterEdit->text();
0658     d->fillTable();
0659 }
0660 
0661 void KoCsvImportDialog::genericDelimiterChanged( const QString & )
0662 {
0663     d->dialog->m_radioOther->setChecked ( true );
0664     delimiterClicked(d->dialog->m_radioOther->group()->id(d->dialog->m_radioOther)); // other
0665 }
0666 
0667 void KoCsvImportDialog::formatChanged( const QString& newValue )
0668 {
0669     QList<QTableWidgetSelectionRange> selectionRanges = d->dialog->m_sheet->selectedRanges();
0670     foreach (const QTableWidgetSelectionRange &selectionRange, selectionRanges) {
0671         for (int j = selectionRange.leftColumn(); j <= selectionRange.rightColumn(); ++j) {
0672              d->dialog->m_sheet->horizontalHeaderItem(j)->setText(newValue);
0673         }
0674     }
0675 }
0676 
0677 void KoCsvImportDialog::delimiterClicked(int id)
0678 {
0679     const QButtonGroup* group = d->dialog->m_radioComma->group();
0680     if (id == group->id(d->dialog->m_radioComma) )
0681         d->delimiter = ',';
0682     else if (id == group->id(d->dialog->m_radioOther))
0683         d->delimiter = d->dialog->m_delimiterEdit->text();
0684     else if (id == group->id(d->dialog->m_radioTab))
0685         d->delimiter = '\t';
0686     else if (id == group->id(d->dialog->m_radioSpace))
0687         d->delimiter = ' ';
0688     else if (id == group->id(d->dialog->m_radioSemicolon))
0689         d->delimiter = ';';
0690 
0691     debugWidgets << "Delimiter" << d->delimiter << "selected.";
0692     d->fillTable();
0693 }
0694 
0695 void KoCsvImportDialog::textquoteSelected(const QString& mark)
0696 {
0697     if (mark == i18n("None"))
0698         d->textQuote = 0;
0699     else
0700         d->textQuote = mark[0];
0701 
0702     d->fillTable();
0703 }
0704 
0705 void KoCsvImportDialog::updateClicked()
0706 {
0707   if ( !d->checkUpdateRange() )
0708     return;
0709 
0710   d->startRow = d->dialog->m_rowStart->value() - 1;
0711   d->endRow   = d->dialog->m_rowEnd->value();
0712 
0713   d->startCol  = d->dialog->m_colStart->value() - 1;
0714   d->endCol    = d->dialog->m_colEnd->value();
0715 
0716   d->fillTable();
0717 }
0718 
0719 bool KoCsvImportDialog::Private::checkUpdateRange()
0720 {
0721     if ((dialog->m_rowStart->value() > dialog->m_rowEnd->value()) ||
0722         (dialog->m_colStart->value() > dialog->m_colEnd->value()))
0723     {
0724         KMessageBox::error(0, i18n("Please check the ranges you specified. The start value must be lower than the end value."));
0725         return false;
0726     }
0727     return true;
0728 }
0729 
0730 void KoCsvImportDialog::currentCellChanged(int, int col)
0731 {
0732     const QString header = d->dialog->m_sheet->model()->headerData(col, Qt::Horizontal).toString();
0733     const int index = d->dialog->m_formatComboBox->findText(header);
0734     d->dialog->m_formatComboBox->setCurrentIndex(index > -1 ? index : 0);
0735 }
0736 
0737 void KoCsvImportDialog::ignoreDuplicatesChanged(int)
0738 {
0739   if (d->dialog->m_ignoreDuplicates->isChecked())
0740     d->ignoreDuplicates = true;
0741   else
0742     d->ignoreDuplicates = false;
0743   d->fillTable();
0744 }
0745 
0746 QTextCodec* KoCsvImportDialog::Private::updateCodec() const
0747 {
0748     const QString strCodec( KCharsets::charsets()->encodingForName( dialog->comboBoxEncoding->currentText() ) );
0749     debugWidgets <<"Encoding:" << strCodec;
0750 
0751     bool ok = false;
0752     QTextCodec* codec = QTextCodec::codecForName( strCodec.toUtf8() );
0753 
0754     // If QTextCodec has not found a valid encoding, so try with KCharsets.
0755     if ( codec )
0756     {
0757         ok = true;
0758     }
0759     else
0760     {
0761         codec = KCharsets::charsets()->codecForName( strCodec, ok );
0762     }
0763 
0764     // Still nothing?
0765     if ( !codec || !ok )
0766     {
0767         // Default: UTF-8
0768         warnWidgets << "Cannot find encoding:" << strCodec;
0769         // ### TODO: what parent to use?
0770         KMessageBox::error( 0, i18n("Cannot find encoding: %1", strCodec ) );
0771         return 0;
0772     }
0773 
0774     return codec;
0775 }
0776 
0777 void KoCsvImportDialog::encodingChanged(const QString &)
0778 {
0779     QTextCodec* codec = d->updateCodec();
0780 
0781     if ( codec )
0782     {
0783         d->codec = codec;
0784         d->fillTable();
0785     }
0786 }
0787 #include "KoCsvImportDialog.moc"