1 /* This file is part of the KDE project
2 Copyright (C) 1999 David Faure <faure@kde.org>
3 Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 #include "KoCsvImportDialog.h"
22
23 // Qt
24 #include <QButtonGroup>
25 #include <QTextCodec>
26 #include <QTextStream>
27
28 #include <QTableWidget>
29 #include <QTableWidgetSelectionRange>
30
31 // KF5
32 #include <kcharsets.h>
33 #include <kconfig.h>
34 #include <WidgetsDebug.h>
35 #include <klocalizedstring.h>
36 #include <kmessagebox.h>
37 #include <ksharedconfig.h>
38
39 #include "ui_KoCsvImportDialog.h"
40
41 class KoCsvImportWidget : public QWidget, public Ui::KoCsvImportWidget
42 {
43 Q_OBJECT
44 public:
KoCsvImportWidget(QWidget * parent)45 explicit KoCsvImportWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
46 };
47
48
49 class Q_DECL_HIDDEN KoCsvImportDialog::Private
50 {
51 public:
52 KoCsvImportDialog* q;
53 KoCsvImportWidget* dialog;
54
55 bool rowsAdjusted;
56 bool columnsAdjusted;
57 int startRow;
58 int startCol;
59 int endRow;
60 int endCol;
61 QChar textQuote;
62 QString delimiter;
63 QString commentSymbol;
64 bool ignoreDuplicates;
65 QByteArray data;
66 QTextCodec* codec;
67 QStringList formatList; ///< List of the column formats
68
Private(KoCsvImportDialog * qq)69 explicit Private(KoCsvImportDialog* qq) : q(qq) {}
70 void loadSettings();
71 void saveSettings();
72 void fillTable();
73 void setText(int row, int col, const QString& text);
74 void adjustRows(int iRows);
75 void adjustCols(int iCols);
76 bool checkUpdateRange();
77 QTextCodec* updateCodec() const;
78 };
79
KoCsvImportDialog(QWidget * parent)80 KoCsvImportDialog::KoCsvImportDialog(QWidget* parent)
81 : KoDialog(parent)
82 , d(new Private(this))
83 {
84 d->dialog = new KoCsvImportWidget(this);
85 d->rowsAdjusted = false;
86 d->columnsAdjusted = false;
87 d->startRow = 0;
88 d->startCol = 0;
89 d->endRow = -1;
90 d->endCol = -1;
91 d->textQuote = QChar('"');
92 d->delimiter = QString(',');
93 d->commentSymbol = QString('#');
94 d->ignoreDuplicates = false;
95 d->codec = QTextCodec::codecForName("UTF-8");
96
97 setButtons( KoDialog::Ok|KoDialog::Cancel );
98 setCaption( i18n( "Import Data" ) );
99
100 QStringList encodings;
101 encodings << i18nc( "Descriptive encoding name", "Recommended ( %1 )" ,"UTF-8" );
102 encodings << i18nc( "Descriptive encoding name", "Locale ( %1 )" ,QString(QTextCodec::codecForLocale()->name() ));
103 encodings += KCharsets::charsets()->descriptiveEncodingNames();
104 // Add a few non-standard encodings, which might be useful for text files
105 const QString description(i18nc("Descriptive encoding name","Other ( %1 )"));
106 encodings << description.arg("Apple Roman"); // Apple
107 encodings << description.arg("IBM 850") << description.arg("IBM 866"); // MS DOS
108 encodings << description.arg("CP 1258"); // Windows
109 d->dialog->comboBoxEncoding->insertItems( 0, encodings );
110
111 setDataTypes(Generic|Text|Date|None);
112
113 // XXX: Qt3->Q4
114 //d->dialog->m_sheet->setReadOnly( true );
115
116 d->loadSettings();
117
118 //resize(sizeHint());
119 resize( 600, 400 ); // Try to show as much as possible of the table view
120 setMainWidget(d->dialog);
121
122 d->dialog->m_sheet->setSelectionMode( QAbstractItemView::MultiSelection );
123
124 QButtonGroup* buttonGroup = new QButtonGroup( this );
125 buttonGroup->addButton(d->dialog->m_radioComma, 0);
126 buttonGroup->addButton(d->dialog->m_radioSemicolon, 1);
127 buttonGroup->addButton(d->dialog->m_radioSpace, 2);
128 buttonGroup->addButton(d->dialog->m_radioTab, 3);
129 buttonGroup->addButton(d->dialog->m_radioOther, 4);
130
131 connect(d->dialog->m_formatComboBox, SIGNAL(activated(QString)),
132 this, SLOT(formatChanged(QString)));
133 connect(buttonGroup, SIGNAL(buttonClicked(int)),
134 this, SLOT(delimiterClicked(int)));
135 connect(d->dialog->m_delimiterEdit, SIGNAL(returnPressed()),
136 this, SLOT(returnPressed()));
137 connect(d->dialog->m_delimiterEdit, SIGNAL(textChanged(QString)),
138 this, SLOT(genericDelimiterChanged(QString)));
139 connect(d->dialog->m_comboQuote, SIGNAL(activated(QString)),
140 this, SLOT(textquoteSelected(QString)));
141 connect(d->dialog->m_sheet, SIGNAL(currentCellChanged(int,int,int,int)),
142 this, SLOT(currentCellChanged(int,int)));
143 connect(d->dialog->m_ignoreDuplicates, SIGNAL(stateChanged(int)),
144 this, SLOT(ignoreDuplicatesChanged(int)));
145 connect(d->dialog->m_updateButton, SIGNAL(clicked()),
146 this, SLOT(updateClicked()));
147 connect(d->dialog->comboBoxEncoding, SIGNAL(textChanged(QString)),
148 this, SLOT(encodingChanged(QString)));
149 }
150
151
~KoCsvImportDialog()152 KoCsvImportDialog::~KoCsvImportDialog()
153 {
154 d->saveSettings();
155 delete d;
156 }
157
158
159 // ----------------------------------------------------------------
160 // public methods
161
162
setData(const QByteArray & data)163 void KoCsvImportDialog::setData( const QByteArray& data )
164 {
165 d->data = data;
166 d->fillTable();
167 }
168
169
firstRowContainHeaders() const170 bool KoCsvImportDialog::firstRowContainHeaders() const
171 {
172 return d->dialog->m_firstRowHeader->isChecked();
173 }
174
175
firstColContainHeaders() const176 bool KoCsvImportDialog::firstColContainHeaders() const
177 {
178 return d->dialog->m_firstColHeader->isChecked();
179 }
180
181
rows() const182 int KoCsvImportDialog::rows() const
183 {
184 int rows = d->dialog->m_sheet->rowCount();
185
186 if ( d->endRow >= 0 )
187 rows = d->endRow - d->startRow + 1;
188
189 return rows;
190 }
191
192
cols() const193 int KoCsvImportDialog::cols() const
194 {
195 int cols = d->dialog->m_sheet->columnCount();
196
197 if ( d->endCol >= 0 )
198 cols = d->endCol - d->startCol + 1;
199
200 return cols;
201 }
202
203
text(int row,int col) const204 QString KoCsvImportDialog::text(int row, int col) const
205 {
206 // Check for overflow.
207 if ( row >= rows() || col >= cols())
208 return QString();
209
210 QTableWidgetItem* item = d->dialog->m_sheet->item( row - d->startRow, col - d->startCol );
211 if ( !item )
212 return QString();
213 return item->text();
214 }
215
setDataTypes(DataTypes dataTypes)216 void KoCsvImportDialog::setDataTypes(DataTypes dataTypes)
217 {
218 d->formatList.clear();
219 if (dataTypes & Generic)
220 d->formatList << i18n("Generic");
221 if (dataTypes & Text)
222 d->formatList << i18n("Text");
223 if (dataTypes & Date)
224 d->formatList << i18n("Date");
225 if (dataTypes & Currency)
226 d->formatList << i18n("Currency");
227 if (dataTypes & None)
228 d->formatList << i18n("None");
229 d->dialog->m_formatComboBox->insertItems(0, d->formatList);
230 }
231
setDataWidgetEnabled(bool enable)232 void KoCsvImportDialog::setDataWidgetEnabled(bool enable)
233 {
234 d->dialog->m_tabWidget->setTabEnabled(0, enable);
235 }
236
decimalSymbol() const237 QString KoCsvImportDialog::decimalSymbol() const
238 {
239 return d->dialog->m_decimalSymbol->text();
240 }
241
setDecimalSymbol(const QString & symbol)242 void KoCsvImportDialog::setDecimalSymbol(const QString& symbol)
243 {
244 d->dialog->m_decimalSymbol->setText(symbol);
245 }
246
thousandsSeparator() const247 QString KoCsvImportDialog::thousandsSeparator() const
248 {
249 return d->dialog->m_thousandsSeparator->text();
250 }
251
setThousandsSeparator(const QString & separator)252 void KoCsvImportDialog::setThousandsSeparator(const QString& separator)
253 {
254 d->dialog->m_thousandsSeparator->setText(separator);
255 }
256
delimiter() const257 QString KoCsvImportDialog::delimiter() const
258 {
259 return d->delimiter;
260 }
261
setDelimiter(const QString & delimit)262 void KoCsvImportDialog::setDelimiter(const QString& delimit)
263 {
264 d->delimiter = delimit;
265 if (delimit == ",")
266 d->dialog->m_radioComma->setChecked(true);
267 else if (delimit == "\t")
268 d->dialog->m_radioTab->setChecked(true);
269 else if (delimit == " ")
270 d->dialog->m_radioSpace->setChecked(true);
271 else if (delimit == ";")
272 d->dialog->m_radioSemicolon->setChecked(true);
273 else {
274 d->dialog->m_radioOther->setChecked(true);
275 d->dialog->m_delimiterEdit->setText(delimit);
276 }
277 }
278
279
280 // ----------------------------------------------------------------
281
282
loadSettings()283 void KoCsvImportDialog::Private::loadSettings()
284 {
285 KConfigGroup configGroup = KSharedConfig::openConfig()->group("CSVDialog Settings");
286 textQuote = configGroup.readEntry("textQuote", "\"").at(0);
287 delimiter = configGroup.readEntry("delimiter", ",");
288 ignoreDuplicates = configGroup.readEntry("ignoreDups", false);
289 const QString codecText = configGroup.readEntry("codec", "");
290
291 // update widgets
292 if (!codecText.isEmpty()) {
293 dialog->comboBoxEncoding->setCurrentIndex(dialog->comboBoxEncoding->findText(codecText));
294 codec = updateCodec();
295 }
296 q->setDelimiter(delimiter);
297 dialog->m_ignoreDuplicates->setChecked(ignoreDuplicates);
298 dialog->m_comboQuote->setCurrentIndex(textQuote == '\'' ? 1 : textQuote == '"' ? 0 : 2);
299 }
300
saveSettings()301 void KoCsvImportDialog::Private::saveSettings()
302 {
303 KConfigGroup configGroup = KSharedConfig::openConfig()->group("CSVDialog Settings");
304 configGroup.writeEntry("textQuote", QString(textQuote));
305 configGroup.writeEntry("delimiter", delimiter);
306 configGroup.writeEntry("ignoreDups", ignoreDuplicates);
307 configGroup.writeEntry("codec", dialog->comboBoxEncoding->currentText());
308 configGroup.sync();
309 }
310
fillTable()311 void KoCsvImportDialog::Private::fillTable()
312 {
313 int row, column;
314 bool lastCharDelimiter = false;
315 enum { Start, InQuotedField, MaybeQuotedFieldEnd, QuotedFieldEnd,
316 MaybeInNormalField, InNormalField } state = Start;
317
318 QChar x;
319 QString field;
320
321 QApplication::setOverrideCursor(Qt::WaitCursor);
322
323 dialog->m_sheet->setRowCount(0);
324 dialog->m_sheet->setColumnCount(0);
325
326 int maxColumn = 1;
327 row = column = 1;
328 QTextStream inputStream(data, QIODevice::ReadOnly);
329 debugWidgets <<"Encoding:" << codec->name();
330 inputStream.setCodec( codec );
331
332 int delimiterIndex = 0;
333 const int delimiterLength = delimiter.size();
334 bool lastCharWasCr = false; // Last character was a Carriage Return
335 while (!inputStream.atEnd())
336 {
337 inputStream >> x; // read one char
338
339 // ### TODO: we should perhaps skip all other control characters
340 if ( x == '\r' )
341 {
342 // We have a Carriage Return, assume that its role is the one of a LineFeed
343 lastCharWasCr = true;
344 x = '\n'; // Replace by Line Feed
345 }
346 else if ( x == '\n' && lastCharWasCr )
347 {
348 // The end of line was already handled by the Carriage Return, so do nothing for this character
349 lastCharWasCr = false;
350 continue;
351 }
352 else if ( x == QChar( 0xc ) )
353 {
354 // We have a FormFeed, skip it
355 lastCharWasCr = false;
356 continue;
357 }
358 else
359 {
360 lastCharWasCr = false;
361 }
362
363 if ( column > maxColumn )
364 maxColumn = column;
365 switch (state)
366 {
367 case Start :
368 if (x == textQuote)
369 {
370 state = InQuotedField;
371 }
372 else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
373 {
374 field += x;
375 delimiterIndex++;
376 if (field.right(delimiterIndex) == delimiter)
377 {
378 if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
379 column += delimiterLength;
380 lastCharDelimiter = true;
381 field.clear();
382 delimiterIndex = 0;
383 state = Start;
384 }
385 else if (delimiterIndex >= delimiterLength)
386 delimiterIndex = 0;
387 }
388 else if (x == '\n')
389 {
390 ++row;
391 column = 1;
392 if ( row > ( endRow - startRow ) && endRow >= 0 )
393 break;
394 }
395 else
396 {
397 field += x;
398 state = MaybeInNormalField;
399 }
400 break;
401 case InQuotedField :
402 if (x == textQuote)
403 {
404 state = MaybeQuotedFieldEnd;
405 }
406 else if (x == '\n')
407 {
408 setText(row - startRow, column - startCol, field);
409 field.clear();
410
411 ++row;
412 column = 1;
413 if ( row > ( endRow - startRow ) && endRow >= 0 )
414 break;
415
416 state = Start;
417 }
418 else
419 {
420 field += x;
421 }
422 break;
423 case MaybeQuotedFieldEnd :
424 if (x == textQuote)
425 {
426 field += x;
427 state = InQuotedField;
428 }
429 else if (x == '\n')
430 {
431 setText(row - startRow, column - startCol, field);
432 field.clear();
433 ++row;
434 column = 1;
435 if ( row > ( endRow - startRow ) && endRow >= 0 )
436 break;
437 state = Start;
438 }
439 else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
440 {
441 field += x;
442 delimiterIndex++;
443 if (field.right(delimiterIndex) == delimiter)
444 {
445 setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
446 field.clear();
447 if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
448 column += delimiterLength;
449 lastCharDelimiter = true;
450 field.clear();
451 delimiterIndex = 0;
452 }
453 else if (delimiterIndex >= delimiterLength)
454 delimiterIndex = 0;
455 state = Start;
456 }
457 else
458 {
459 state = QuotedFieldEnd;
460 }
461 break;
462 case QuotedFieldEnd :
463 if (x == '\n')
464 {
465 setText(row - startRow, column - startCol, field);
466 field.clear();
467 ++row;
468 column = 1;
469 if ( row > ( endRow - startRow ) && endRow >= 0 )
470 break;
471 state = Start;
472 }
473 else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
474 {
475 field += x;
476 delimiterIndex++;
477 if (field.right(delimiterIndex) == delimiter)
478 {
479 setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
480 field.clear();
481 if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
482 column += delimiterLength;
483 lastCharDelimiter = true;
484 field.clear();
485 delimiterIndex = 0;
486 }
487 else if (delimiterIndex >= delimiterLength)
488 delimiterIndex = 0;
489 state = Start;
490 }
491 else
492 {
493 state = QuotedFieldEnd;
494 }
495 break;
496 case MaybeInNormalField :
497 if (x == textQuote)
498 {
499 field.clear();
500 state = InQuotedField;
501 break;
502 }
503 state = InNormalField;
504 case InNormalField :
505 if (x == '\n')
506 {
507 setText(row - startRow, column - startCol, field);
508 field.clear();
509 ++row;
510 column = 1;
511 if ( row > ( endRow - startRow ) && endRow >= 0 )
512 break;
513 state = Start;
514 }
515 else if (delimiterIndex < delimiterLength && x == delimiter.at(delimiterIndex))
516 {
517 field += x;
518 delimiterIndex++;
519 if (field.right(delimiterIndex) == delimiter)
520 {
521 setText(row - startRow, column - startCol, field.left(field.count()-delimiterIndex));
522 field.clear();
523 if ((ignoreDuplicates == false) || (lastCharDelimiter == false))
524 column += delimiterLength;
525 lastCharDelimiter = true;
526 field.clear();
527 delimiterIndex = 0;
528 }
529 else if (delimiterIndex >= delimiterLength)
530 delimiterIndex = 0;
531 state = Start;
532 }
533 else
534 {
535 field += x;
536 }
537 }
538 if (delimiter.isEmpty() || x != delimiter.at(0))
539 lastCharDelimiter = false;
540 }
541
542 if ( !field.isEmpty() )
543 {
544 // the last line of the file had not any line end
545 setText(row - startRow, column - startCol, field);
546 ++row;
547 field.clear();
548 }
549 if (row) row--; // row is higher by 1, so reduce it
550
551 columnsAdjusted = true;
552 adjustRows( row - startRow );
553 adjustCols( maxColumn - startCol );
554
555 for (column = 0; column < dialog->m_sheet->columnCount(); ++column)
556 {
557 const QTableWidgetItem* headerItem = dialog->m_sheet->horizontalHeaderItem(column);
558 if (!headerItem || !formatList.contains(headerItem->text())) {
559 dialog->m_sheet->setHorizontalHeaderItem(column, new QTableWidgetItem(i18n("Generic")));
560 }
561 }
562
563 dialog->m_rowStart->setMinimum(1);
564 dialog->m_colStart->setMinimum(1);
565 dialog->m_rowStart->setMaximum(row);
566 dialog->m_colStart->setMaximum(maxColumn);
567
568 dialog->m_rowEnd->setMinimum(1);
569 dialog->m_colEnd->setMinimum(1);
570 dialog->m_rowEnd->setMaximum(row);
571 dialog->m_colEnd->setMaximum(maxColumn);
572 dialog->m_rowEnd->setValue(endRow == -1 ? row : endRow);
573 dialog->m_colEnd->setValue(endCol == -1 ? maxColumn : endCol);
574
575 QApplication::restoreOverrideCursor();
576 }
577
dataType(int col) const578 KoCsvImportDialog::DataType KoCsvImportDialog::dataType(int col) const
579 {
580 const QString header = d->dialog->m_sheet->model()->headerData(col, Qt::Horizontal).toString();
581
582 if (header == i18n("Generic"))
583 return Generic;
584 else if (header == i18n("Text"))
585 return Text;
586 else if (header == i18n("Date"))
587 return Date;
588 else if (header == i18n("Currency"))
589 return Currency;
590 else if (header == i18n("None"))
591 return None;
592 return Generic;
593 }
594
setText(int row,int col,const QString & text)595 void KoCsvImportDialog::Private::setText(int row, int col, const QString& text)
596 {
597 if (row < 1 || col < 1) // skipped by the user
598 return;
599
600 if ((row > (endRow - startRow) && endRow > 0) || (col > (endCol - startCol) && endCol > 0))
601 return;
602
603 if (dialog->m_sheet->rowCount() < row)
604 {
605 dialog->m_sheet->setRowCount(row + 5000); /* We add 5000 at a time to limit recalculations */
606 rowsAdjusted = true;
607 }
608
609 if (dialog->m_sheet->columnCount() < col)
610 {
611 dialog->m_sheet->setColumnCount(col);
612 columnsAdjusted = true;
613 }
614
615 QTableWidgetItem* item = dialog->m_sheet->item(row - 1, col - 1);
616 if (!item) {
617 item = new QTableWidgetItem();
618 dialog->m_sheet->setItem(row - 1, col - 1, item);
619 }
620 item->setText(text);
621 }
622
623 /*
624 * Called after the first fillTable() when number of rows are unknown.
625 */
adjustRows(int iRows)626 void KoCsvImportDialog::Private::adjustRows(int iRows)
627 {
628 if (rowsAdjusted)
629 {
630 dialog->m_sheet->setRowCount(iRows);
631 rowsAdjusted = false;
632 }
633 }
634
adjustCols(int iCols)635 void KoCsvImportDialog::Private::adjustCols(int iCols)
636 {
637 if (columnsAdjusted)
638 {
639 dialog->m_sheet->setColumnCount(iCols);
640 columnsAdjusted = false;
641
642 if (endCol == -1)
643 {
644 if (iCols > (endCol - startCol))
645 iCols = endCol - startCol;
646
647 dialog->m_sheet->setColumnCount(iCols);
648 }
649 }
650 }
651
returnPressed()652 void KoCsvImportDialog::returnPressed()
653 {
654 if (d->dialog->m_radioOther->isChecked())
655 return;
656
657 d->delimiter = d->dialog->m_delimiterEdit->text();
658 d->fillTable();
659 }
660
genericDelimiterChanged(const QString &)661 void KoCsvImportDialog::genericDelimiterChanged( const QString & )
662 {
663 d->dialog->m_radioOther->setChecked ( true );
664 delimiterClicked(d->dialog->m_radioOther->group()->id(d->dialog->m_radioOther)); // other
665 }
666
formatChanged(const QString & newValue)667 void KoCsvImportDialog::formatChanged( const QString& newValue )
668 {
669 QList<QTableWidgetSelectionRange> selectionRanges = d->dialog->m_sheet->selectedRanges();
670 foreach (const QTableWidgetSelectionRange &selectionRange, selectionRanges) {
671 for (int j = selectionRange.leftColumn(); j <= selectionRange.rightColumn(); ++j) {
672 d->dialog->m_sheet->horizontalHeaderItem(j)->setText(newValue);
673 }
674 }
675 }
676
delimiterClicked(int id)677 void KoCsvImportDialog::delimiterClicked(int id)
678 {
679 const QButtonGroup* group = d->dialog->m_radioComma->group();
680 if (id == group->id(d->dialog->m_radioComma) )
681 d->delimiter = ',';
682 else if (id == group->id(d->dialog->m_radioOther))
683 d->delimiter = d->dialog->m_delimiterEdit->text();
684 else if (id == group->id(d->dialog->m_radioTab))
685 d->delimiter = '\t';
686 else if (id == group->id(d->dialog->m_radioSpace))
687 d->delimiter = ' ';
688 else if (id == group->id(d->dialog->m_radioSemicolon))
689 d->delimiter = ';';
690
691 debugWidgets << "Delimiter" << d->delimiter << "selected.";
692 d->fillTable();
693 }
694
textquoteSelected(const QString & mark)695 void KoCsvImportDialog::textquoteSelected(const QString& mark)
696 {
697 if (mark == i18n("None"))
698 d->textQuote = 0;
699 else
700 d->textQuote = mark[0];
701
702 d->fillTable();
703 }
704
updateClicked()705 void KoCsvImportDialog::updateClicked()
706 {
707 if ( !d->checkUpdateRange() )
708 return;
709
710 d->startRow = d->dialog->m_rowStart->value() - 1;
711 d->endRow = d->dialog->m_rowEnd->value();
712
713 d->startCol = d->dialog->m_colStart->value() - 1;
714 d->endCol = d->dialog->m_colEnd->value();
715
716 d->fillTable();
717 }
718
checkUpdateRange()719 bool KoCsvImportDialog::Private::checkUpdateRange()
720 {
721 if ((dialog->m_rowStart->value() > dialog->m_rowEnd->value()) ||
722 (dialog->m_colStart->value() > dialog->m_colEnd->value()))
723 {
724 KMessageBox::error(0, i18n("Please check the ranges you specified. The start value must be lower than the end value."));
725 return false;
726 }
727 return true;
728 }
729
currentCellChanged(int,int col)730 void KoCsvImportDialog::currentCellChanged(int, int col)
731 {
732 const QString header = d->dialog->m_sheet->model()->headerData(col, Qt::Horizontal).toString();
733 const int index = d->dialog->m_formatComboBox->findText(header);
734 d->dialog->m_formatComboBox->setCurrentIndex(index > -1 ? index : 0);
735 }
736
ignoreDuplicatesChanged(int)737 void KoCsvImportDialog::ignoreDuplicatesChanged(int)
738 {
739 if (d->dialog->m_ignoreDuplicates->isChecked())
740 d->ignoreDuplicates = true;
741 else
742 d->ignoreDuplicates = false;
743 d->fillTable();
744 }
745
updateCodec() const746 QTextCodec* KoCsvImportDialog::Private::updateCodec() const
747 {
748 const QString strCodec( KCharsets::charsets()->encodingForName( dialog->comboBoxEncoding->currentText() ) );
749 debugWidgets <<"Encoding:" << strCodec;
750
751 bool ok = false;
752 QTextCodec* codec = QTextCodec::codecForName( strCodec.toUtf8() );
753
754 // If QTextCodec has not found a valid encoding, so try with KCharsets.
755 if ( codec )
756 {
757 ok = true;
758 }
759 else
760 {
761 codec = KCharsets::charsets()->codecForName( strCodec, ok );
762 }
763
764 // Still nothing?
765 if ( !codec || !ok )
766 {
767 // Default: UTF-8
768 warnWidgets << "Cannot find encoding:" << strCodec;
769 // ### TODO: what parent to use?
770 KMessageBox::error( 0, i18n("Cannot find encoding: %1", strCodec ) );
771 return 0;
772 }
773
774 return codec;
775 }
776
encodingChanged(const QString &)777 void KoCsvImportDialog::encodingChanged(const QString &)
778 {
779 QTextCodec* codec = d->updateCodec();
780
781 if ( codec )
782 {
783 d->codec = codec;
784 d->fillTable();
785 }
786 }
787 #include "KoCsvImportDialog.moc"
788