00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <csvimportdialogui.h>
00022 #include <csvimportdialog.h>
00023
00024 #include <qtable.h>
00025 #include <qcheckbox.h>
00026 #include <qcursor.h>
00027 #include <qlineedit.h>
00028 #include <qcombobox.h>
00029 #include <qspinbox.h>
00030 #include <qtextstream.h>
00031 #include <qbuttongroup.h>
00032 #include <qpushbutton.h>
00033 #include <qradiobutton.h>
00034 #include <qtextcodec.h>
00035
00036 #include <kapplication.h>
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kcombobox.h>
00040 #include <kmessagebox.h>
00041 #include <kcharsets.h>
00042
00043
00044 CSVImportDialog::CSVImportDialog(QWidget* parent, QByteArray& fileArray)
00045 : KDialogBase(parent, 0, true, QString::null, Ok|Cancel, No, true),
00046 m_dialog(new DialogUI(this)),
00047 m_adjustRows(false),
00048 m_adjustCols(false),
00049 m_startRow(0),
00050 m_startCol(0),
00051 m_endRow(-1),
00052 m_endCol(-1),
00053 m_textquote('"'),
00054 m_delimiter(","),
00055 m_ignoreDups(false),
00056 m_fileArray(fileArray),
00057 m_codec( QTextCodec::codecForName( "UTF-8" ) )
00058 {
00059 setCaption( i18n( "Import Data" ) );
00060 kapp->restoreOverrideCursor();
00061
00062 QStringList encodings;
00063 encodings << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" );
00064 encodings << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->name() );
00065 encodings += KGlobal::charsets()->descriptiveEncodingNames();
00066
00067 const QString description(i18n("Descriptive encoding name","Other ( %1 )"));
00068 encodings << description.arg("Apple Roman");
00069 encodings << description.arg("IBM 850") << description.arg("IBM 866");
00070 encodings << description.arg("CP 1258");
00071 m_dialog->comboBoxEncoding->insertStringList(encodings);
00072
00073 m_formatList << i18n( "Text" );
00074 m_formatList << i18n( "Number" );
00075
00076
00077 m_formatList << i18n( "Decimal Comma Number" );
00078 m_formatList << i18n( "Decimal Point Number" );
00079 m_dialog->m_formatComboBox->insertStringList( m_formatList );
00080
00081 m_dialog->m_sheet->setReadOnly( true );
00082
00083 fillTable();
00084
00085
00086 resize( 600, 400 );
00087 setMainWidget(m_dialog);
00088
00089 m_dialog->m_sheet->setSelectionMode( QTable::Multi );
00090
00091 connect(m_dialog->m_formatComboBox, SIGNAL(activated( const QString& )),
00092 this, SLOT(formatChanged( const QString& )));
00093 connect(m_dialog->m_delimiterBox, SIGNAL(clicked(int)),
00094 this, SLOT(delimiterClicked(int)));
00095 connect(m_dialog->m_delimiterEdit, SIGNAL(returnPressed()),
00096 this, SLOT(returnPressed()));
00097 connect(m_dialog->m_delimiterEdit, SIGNAL(textChanged ( const QString & )),
00098 this, SLOT(formatChanged ( const QString & ) ));
00099 connect(m_dialog->m_comboQuote, SIGNAL(activated(const QString &)),
00100 this, SLOT(textquoteSelected(const QString &)));
00101 connect(m_dialog->m_sheet, SIGNAL(currentChanged(int, int)),
00102 this, SLOT(currentCellChanged(int, int)));
00103 connect(m_dialog->m_ignoreDuplicates, SIGNAL(stateChanged(int)),
00104 this, SLOT(ignoreDuplicatesChanged(int)));
00105 connect(m_dialog->m_updateButton, SIGNAL(clicked()),
00106 this, SLOT(updateClicked()));
00107 connect(m_dialog->comboBoxEncoding, SIGNAL(textChanged ( const QString & )),
00108 this, SLOT(encodingChanged ( const QString & ) ));
00109 }
00110
00111
00112 CSVImportDialog::~CSVImportDialog()
00113 {
00114 kapp->setOverrideCursor(Qt::waitCursor);
00115 }
00116
00117
00118
00119
00120
00121
00122 bool CSVImportDialog::firstRowContainHeaders()
00123 {
00124 return m_dialog->m_firstRowHeader->isChecked();
00125 }
00126
00127
00128 bool CSVImportDialog::firstColContainHeaders()
00129 {
00130 return m_dialog->m_firstColHeader->isChecked();
00131 }
00132
00133
00134 int CSVImportDialog::rows()
00135 {
00136 int rows = m_dialog->m_sheet->numRows();
00137
00138 if ( m_endRow >= 0 )
00139 rows = m_endRow - m_startRow + 1;
00140
00141 return rows;
00142 }
00143
00144
00145 int CSVImportDialog::cols()
00146 {
00147 int cols = m_dialog->m_sheet->numCols();
00148
00149 if ( m_endCol >= 0 )
00150 cols = m_endCol - m_startCol + 1;
00151
00152 return cols;
00153 }
00154
00155
00156 QString CSVImportDialog::text(int row, int col)
00157 {
00158
00159 if ( row >= rows() || col >= cols())
00160 return QString::null;
00161
00162 return m_dialog->m_sheet->text( row - m_startRow, col - m_startCol );
00163 }
00164
00165
00166
00167
00168
00169 void CSVImportDialog::fillTable( )
00170 {
00171 int row, column;
00172 bool lastCharDelimiter = false;
00173 enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
00174 S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
00175
00176 QChar x;
00177 QString field;
00178
00179 kapp->setOverrideCursor(Qt::waitCursor);
00180
00181 for (row = 0; row < m_dialog->m_sheet->numRows(); ++row)
00182 for (column = 0; column < m_dialog->m_sheet->numCols(); ++column)
00183 m_dialog->m_sheet->clearCell(row, column);
00184
00185 int maxColumn = 1;
00186 row = column = 1;
00187 QTextStream inputStream(m_fileArray, IO_ReadOnly);
00188 kdDebug(30501) << "Encoding: " << m_codec->name() << endl;
00189 inputStream.setCodec( m_codec );
00190
00191 bool lastCharWasCr = false;
00192 while (!inputStream.atEnd())
00193 {
00194 inputStream >> x;
00195
00196
00197 if ( x == '\r' )
00198 {
00199
00200 lastCharWasCr = true;
00201 x = '\n';
00202 }
00203 else if ( x == '\n' && lastCharWasCr )
00204 {
00205
00206 lastCharWasCr = false;
00207 continue;
00208 }
00209 else if ( x == QChar( 0xc ) )
00210 {
00211
00212 lastCharWasCr = false;
00213 continue;
00214 }
00215 else
00216 {
00217 lastCharWasCr = false;
00218 }
00219
00220 if ( column > maxColumn )
00221 maxColumn = column;
00222
00223 switch (state)
00224 {
00225 case S_START :
00226 if (x == m_textquote)
00227 {
00228 state = S_QUOTED_FIELD;
00229 }
00230 else if (x == m_delimiter)
00231 {
00232 if ((m_ignoreDups == false) || (lastCharDelimiter == false))
00233 ++column;
00234 lastCharDelimiter = true;
00235 }
00236 else if (x == '\n')
00237 {
00238 ++row;
00239 column = 1;
00240 if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
00241 break;
00242 }
00243 else
00244 {
00245 field += x;
00246 state = S_MAYBE_NORMAL_FIELD;
00247 }
00248 break;
00249 case S_QUOTED_FIELD :
00250 if (x == m_textquote)
00251 {
00252 state = S_MAYBE_END_OF_QUOTED_FIELD;
00253 }
00254 else if (x == '\n')
00255 {
00256 setText(row - m_startRow, column - m_startCol, field);
00257 field = QString::null;
00258
00259 ++row;
00260 column = 1;
00261 if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
00262 break;
00263
00264 state = S_START;
00265 }
00266 else
00267 {
00268 field += x;
00269 }
00270 break;
00271 case S_MAYBE_END_OF_QUOTED_FIELD :
00272 if (x == m_textquote)
00273 {
00274 field += x;
00275 state = S_QUOTED_FIELD;
00276 }
00277 else if (x == m_delimiter || x == '\n')
00278 {
00279 setText(row - m_startRow, column - m_startCol, field);
00280 field = QString::null;
00281 if (x == '\n')
00282 {
00283 ++row;
00284 column = 1;
00285 if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
00286 break;
00287 }
00288 else
00289 {
00290 if ((m_ignoreDups == false) || (lastCharDelimiter == false))
00291 ++column;
00292 lastCharDelimiter = true;
00293 }
00294 state = S_START;
00295 }
00296 else
00297 {
00298 state = S_END_OF_QUOTED_FIELD;
00299 }
00300 break;
00301 case S_END_OF_QUOTED_FIELD :
00302 if (x == m_delimiter || x == '\n')
00303 {
00304 setText(row - m_startRow, column - m_startCol, field);
00305 field = QString::null;
00306 if (x == '\n')
00307 {
00308 ++row;
00309 column = 1;
00310 if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
00311 break;
00312 }
00313 else
00314 {
00315 if ((m_ignoreDups == false) || (lastCharDelimiter == false))
00316 ++column;
00317 lastCharDelimiter = true;
00318 }
00319 state = S_START;
00320 }
00321 else
00322 {
00323 state = S_END_OF_QUOTED_FIELD;
00324 }
00325 break;
00326 case S_MAYBE_NORMAL_FIELD :
00327 if (x == m_textquote)
00328 {
00329 field = QString::null;
00330 state = S_QUOTED_FIELD;
00331 break;
00332 }
00333 case S_NORMAL_FIELD :
00334 if (x == m_delimiter || x == '\n')
00335 {
00336 setText(row - m_startRow, column - m_startCol, field);
00337 field = QString::null;
00338 if (x == '\n')
00339 {
00340 ++row;
00341 column = 1;
00342 if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
00343 break;
00344 }
00345 else
00346 {
00347 if ((m_ignoreDups == false) || (lastCharDelimiter == false))
00348 ++column;
00349 lastCharDelimiter = true;
00350 }
00351 state = S_START;
00352 }
00353 else
00354 {
00355 field += x;
00356 }
00357 }
00358 if (x != m_delimiter)
00359 lastCharDelimiter = false;
00360 }
00361
00362 if ( !field.isEmpty() )
00363 {
00364
00365 setText(row - m_startRow, column - m_startCol, field);
00366 ++row;
00367 field = QString::null;
00368 }
00369
00370 m_adjustCols = true;
00371 adjustRows( row - m_startRow );
00372 adjustCols( maxColumn - m_startCol );
00373 m_dialog->m_colEnd->setMaxValue( maxColumn );
00374 if ( m_endCol == -1 )
00375 m_dialog->m_colEnd->setValue( maxColumn );
00376
00377
00378 for (column = 0; column < m_dialog->m_sheet->numCols(); ++column)
00379 {
00380 const QString header = m_dialog->m_sheet->horizontalHeader()->label(column);
00381 if ( m_formatList.find( header ) == m_formatList.end() )
00382 m_dialog->m_sheet->horizontalHeader()->setLabel(column, i18n("Text"));
00383
00384 m_dialog->m_sheet->adjustColumn(column);
00385 }
00386 fillComboBox();
00387
00388 kapp->restoreOverrideCursor();
00389 }
00390
00391 void CSVImportDialog::fillComboBox()
00392 {
00393 if ( m_endRow == -1 )
00394 m_dialog->m_rowEnd->setValue( m_dialog->m_sheet->numRows() );
00395 else
00396 m_dialog->m_rowEnd->setValue( m_endRow );
00397
00398 if ( m_endCol == -1 )
00399 m_dialog->m_colEnd->setValue( m_dialog->m_sheet->numCols() );
00400 else
00401 m_dialog->m_colEnd->setValue( m_endCol );
00402
00403 m_dialog->m_rowEnd->setMinValue( 1 );
00404 m_dialog->m_colEnd->setMinValue( 1 );
00405 m_dialog->m_rowEnd->setMaxValue( m_dialog->m_sheet->numRows() );
00406 m_dialog->m_colEnd->setMaxValue( m_dialog->m_sheet->numCols() );
00407
00408 m_dialog->m_rowStart->setMinValue( 1 );
00409 m_dialog->m_colStart->setMinValue( 1 );
00410 m_dialog->m_rowStart->setMaxValue( m_dialog->m_sheet->numRows() );
00411 m_dialog->m_colStart->setMaxValue( m_dialog->m_sheet->numCols() );
00412 }
00413
00414 int CSVImportDialog::headerType(int col)
00415 {
00416 QString header = m_dialog->m_sheet->horizontalHeader()->label(col);
00417
00418 if (header == i18n("Text"))
00419 return TEXT;
00420 else if (header == i18n("Number"))
00421 return NUMBER;
00422 else if (header == i18n("Currency"))
00423 return CURRENCY;
00424 else if ( header == i18n( "Date" ) )
00425 return DATE;
00426 else if ( header == i18n( "Decimal Comma Number" ) )
00427 return COMMANUMBER;
00428 else if ( header == i18n( "Decimal Point Number" ) )
00429 return POINTNUMBER;
00430 else
00431 return TEXT;
00432 }
00433
00434 void CSVImportDialog::setText(int row, int col, const QString& text)
00435 {
00436 if ( row < 1 || col < 1 )
00437 return;
00438
00439 if ( ( row > ( m_endRow - m_startRow ) && m_endRow > 0 ) || ( col > ( m_endCol - m_startCol ) && m_endCol > 0 ) )
00440 return;
00441
00442 if ( m_dialog->m_sheet->numRows() < row )
00443 {
00444 m_dialog->m_sheet->setNumRows( row + 5000 );
00445 m_adjustRows = true;
00446 }
00447
00448 if ( m_dialog->m_sheet->numCols() < col )
00449 {
00450 m_dialog->m_sheet->setNumCols( col );
00451 m_adjustCols = true;
00452 }
00453
00454 m_dialog->m_sheet->setText( row - 1, col - 1, text );
00455 }
00456
00457
00458
00459
00460 void CSVImportDialog::adjustRows(int iRows)
00461 {
00462 if (m_adjustRows)
00463 {
00464 m_dialog->m_sheet->setNumRows( iRows );
00465 m_adjustRows = false;
00466 }
00467 }
00468
00469 void CSVImportDialog::adjustCols(int iCols)
00470 {
00471 if (m_adjustCols)
00472 {
00473 m_dialog->m_sheet->setNumCols( iCols );
00474 m_adjustCols = false;
00475
00476 if ( m_endCol == -1 )
00477 {
00478 if ( iCols > ( m_endCol - m_startCol ) )
00479 iCols = m_endCol - m_startCol;
00480
00481 m_dialog->m_sheet->setNumCols( iCols );
00482 }
00483 }
00484 }
00485
00486 void CSVImportDialog::returnPressed()
00487 {
00488 if (m_dialog->m_delimiterBox->id(m_dialog->m_delimiterBox->selected()) != 4)
00489 return;
00490
00491 m_delimiter = m_dialog->m_delimiterEdit->text();
00492 fillTable();
00493 }
00494
00495 void CSVImportDialog::textChanged ( const QString & )
00496 {
00497 m_dialog->m_radioOther->setChecked ( true );
00498 delimiterClicked(4);
00499 }
00500
00501 void CSVImportDialog::formatChanged( const QString& newValue )
00502 {
00503
00504 for ( int i = 0; i < m_dialog->m_sheet->numSelections(); ++i )
00505 {
00506 QTableSelection select ( m_dialog->m_sheet->selection( i ) );
00507 for ( int j = select.leftCol(); j <= select.rightCol() ; ++j )
00508 {
00509 m_dialog->m_sheet->horizontalHeader()->setLabel( j, newValue );
00510
00511 }
00512 }
00513 }
00514
00515 void CSVImportDialog::delimiterClicked(int id)
00516 {
00517 switch (id)
00518 {
00519 case 0:
00520 m_delimiter = ",";
00521 break;
00522 case 4:
00523 m_delimiter = m_dialog->m_delimiterEdit->text();
00524 break;
00525 case 2:
00526 m_delimiter = "\t";
00527 break;
00528 case 3:
00529 m_delimiter = " ";
00530 break;
00531 case 1:
00532 m_delimiter = ";";
00533 break;
00534 }
00535
00536 fillTable();
00537 }
00538
00539 void CSVImportDialog::textquoteSelected(const QString& mark)
00540 {
00541 if (mark == i18n("None"))
00542 m_textquote = 0;
00543 else
00544 m_textquote = mark[0];
00545
00546 fillTable();
00547 }
00548
00549 void CSVImportDialog::updateClicked()
00550 {
00551 if ( !checkUpdateRange() )
00552 return;
00553
00554 m_startRow = m_dialog->m_rowStart->value() - 1;
00555 m_endRow = m_dialog->m_rowEnd->value();
00556
00557 m_startCol = m_dialog->m_colStart->value() - 1;
00558 m_endCol = m_dialog->m_colEnd->value();
00559
00560 fillTable();
00561 }
00562
00563 bool CSVImportDialog::checkUpdateRange()
00564 {
00565 if ( ( m_dialog->m_rowStart->value() > m_dialog->m_rowEnd->value() )
00566 || ( m_dialog->m_colStart->value() > m_dialog->m_colEnd->value() ) )
00567 {
00568 KMessageBox::error( this, i18n( "Please check the ranges you specified. The start value must be lower than the end value." ) );
00569 return false;
00570 }
00571
00572 return true;
00573 }
00574
00575 void CSVImportDialog::currentCellChanged(int, int col)
00576 {
00577 const QString header = m_dialog->m_sheet->horizontalHeader()->label(col);
00578 m_dialog->m_formatComboBox->setCurrentText( header );
00579 }
00580
00581 void CSVImportDialog::ignoreDuplicatesChanged(int)
00582 {
00583 if (m_dialog->m_ignoreDuplicates->isChecked())
00584 m_ignoreDups = true;
00585 else
00586 m_ignoreDups = false;
00587 fillTable();
00588 }
00589
00590 QTextCodec* CSVImportDialog::getCodec(void) const
00591 {
00592 const QString strCodec( KGlobal::charsets()->encodingForName( m_dialog->comboBoxEncoding->currentText() ) );
00593 kdDebug(30502) << "Encoding: " << strCodec << endl;
00594
00595 bool ok = false;
00596 QTextCodec* codec = QTextCodec::codecForName( strCodec.utf8() );
00597
00598
00599 if ( codec )
00600 {
00601 ok = true;
00602 }
00603 else
00604 {
00605 codec = KGlobal::charsets()->codecForName( strCodec, ok );
00606 }
00607
00608
00609 if ( !codec || !ok )
00610 {
00611
00612 kdWarning(30502) << "Cannot find encoding:" << strCodec << endl;
00613
00614 KMessageBox::error( 0, i18n("Cannot find encoding: %1").arg( strCodec ) );
00615 return 0;
00616 }
00617
00618 return codec;
00619 }
00620
00621 void CSVImportDialog::encodingChanged ( const QString & )
00622 {
00623 QTextCodec* codec = getCodec();
00624
00625 if ( codec )
00626 {
00627 m_codec = codec;
00628 fillTable();
00629 }
00630 }
00631
00632
00633 #include <csvimportdialog.moc>