00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <qbuttongroup.h>
00029 #include <qcheckbox.h>
00030 #include <qclipboard.h>
00031 #include <qlabel.h>
00032 #include <qlineedit.h>
00033 #include <qmime.h>
00034 #include <qpushbutton.h>
00035 #include <qradiobutton.h>
00036 #include <qtable.h>
00037 #include <qlayout.h>
00038 #include <qfiledialog.h>
00039 #include <qpainter.h>
00040 #include <qtextcodec.h>
00041 #include <qtimer.h>
00042 #include <qfontmetrics.h>
00043
00044 #include <kapplication.h>
00045 #include <kdebug.h>
00046 #include <kdialogbase.h>
00047 #include <kfiledialog.h>
00048 #include <klocale.h>
00049 #include <kmessagebox.h>
00050 #include <kglobalsettings.h>
00051 #include <kiconloader.h>
00052 #include <kcharsets.h>
00053 #include <knuminput.h>
00054 #include <kprogress.h>
00055
00056 #include <kexiutils/identifier.h>
00057 #include <kexiutils/utils.h>
00058 #include <core/kexi.h>
00059 #include <core/kexiproject.h>
00060 #include <core/kexipart.h>
00061 #include <core/kexipartinfo.h>
00062 #include <core/keximainwindow.h>
00063 #include <core/kexiguimsghandler.h>
00064 #include <kexidb/connection.h>
00065 #include <kexidb/tableschema.h>
00066 #include <kexidb/transaction.h>
00067 #include <widget/kexicharencodingcombobox.h>
00068
00069 #include "kexicsvimportdialog.h"
00070 #include "kexicsvimportoptionsdlg.h"
00071 #include "kexicsvwidgets.h"
00072
00073 #ifdef Q_WS_WIN
00074 #include <krecentdirs.h>
00075 #include <windows.h>
00076 #endif
00077
00078 #if 0
00079 #include <kspread_cell.h>
00080 #include <kspread_doc.h>
00081 #include <kspread_sheet.h>
00082 #include <kspread_undo.h>
00083 #include <kspread_view.h>
00084 #endif
00085
00086 #define _IMPORT_ICON "table"
00087 #define _TEXT_TYPE 0
00088 #define _NUMBER_TYPE 1
00089 #define _DATE_TYPE 2
00090 #define _TIME_TYPE 3
00091 #define _DATETIME_TYPE 4
00092 #define _PK_FLAG 5
00093
00094
00095 #define _NO_TYPE_YET -1 //allows to accept a number of empty cells, before something non-empty
00096 #define _FP_NUMBER_TYPE 255 //_NUMBER_TYPE variant
00097 #define MAX_COLUMNS 100 //max 100 columns is reasonable
00098
00099 class KexiCSVImportDialogTable : public QTable
00100 {
00101 public:
00102 KexiCSVImportDialogTable( QWidget * parent = 0, const char * name = 0 )
00103 : QTable(parent, name) {
00104 f = font();
00105 f.setBold(true);
00106 }
00107 virtual void paintCell( QPainter * p, int row, int col, const QRect & cr, bool selected, const QColorGroup & cg ) {
00108 if (row==0)
00109 p->setFont(f);
00110 else
00111 p->setFont(font());
00112 QTable::paintCell(p, row, col, cr, selected, cg);
00113 }
00114 virtual void setColumnWidth( int col, int w ) {
00115
00116 QTable::setColumnWidth( col, w + 16 );
00117 }
00118 QFont f;
00119 };
00120
00122 void installRecursiveEventFilter(QObject *filter, QObject *object)
00123 {
00124 object->installEventFilter(filter);
00125
00126 if (!object->children())
00127 return;
00128
00129 QObjectList list = *object->children();
00130 for(QObject *obj = list.first(); obj; obj = list.next())
00131 installRecursiveEventFilter(filter, obj);
00132 }
00133
00134 KexiCSVImportDialog::KexiCSVImportDialog( Mode mode, KexiMainWindow* mainWin,
00135 QWidget * parent, const char * name
00136 )
00137 : KDialogBase(
00138 KDialogBase::Plain,
00139 i18n( "Import CSV Data File" )
00141 ,
00142 (mode==File ? User1 : (ButtonCode)0) |Ok|Cancel,
00143 Ok,
00144 parent,
00145 name ? name : "KexiCSVImportDialog",
00146 true,
00147 false,
00148 KGuiItem( i18n("&Options"))
00149 ),
00150 m_mainWin(mainWin),
00151 m_cancelled( false ),
00152 m_adjustRows( 0 ),
00153 m_startline( 0 ),
00154 m_textquote( QString(KEXICSV_DEFAULT_TEXT_QUOTE)[0] ),
00155 m_mode(mode),
00156 m_prevSelectedCol(-1),
00157 m_columnsAdjusted(false),
00158 m_1stRowForFieldNamesDetected(false),
00159 m_firstFillTableCall(true),
00160 m_blockUserEvents(false),
00161 m_primaryKeyColumn(-1),
00162 m_dialogCancelled(false),
00163 m_conn(0),
00164 m_destinationTableSchema(0)
00165 {
00166 setWFlags(getWFlags() | Qt::WStyle_Maximize | Qt::WStyle_SysMenu);
00167 hide();
00168 setButtonOK(KGuiItem( i18n("&Import..."), _IMPORT_ICON));
00169
00170 m_typeNames.resize(5);
00171 m_typeNames[0] = i18n("text");
00172 m_typeNames[1] = i18n("number");
00173 m_typeNames[2] = i18n("date");
00174 m_typeNames[3] = i18n("time");
00175 m_typeNames[4] = i18n("date/time");
00176
00177 kapp->config()->setGroup("ImportExport");
00178 m_maximumRowsForPreview = kapp->config()->readNumEntry("MaximumRowsForPreviewInImportDialog", MAX_COLUMNS);
00179
00180 m_pkIcon = SmallIcon("key");
00181
00182 m_uniquenessTest.setAutoDelete(true);
00183
00184 setIcon(DesktopIcon(_IMPORT_ICON));
00185 setSizeGripEnabled( TRUE );
00186
00187 m_encoding = QString::fromLatin1(KGlobal::locale()->encoding());
00188 m_file = 0;
00189 m_inputStream = 0;
00190
00191 QVBoxLayout *lyr = new QVBoxLayout(plainPage(), 0, KDialogBase::spacingHint(), "lyr");
00192
00193 m_infoLbl = new KexiCSVInfoLabel(
00194 m_mode==File ? i18n("Preview of data from file:")
00195 : i18n("Preview of data from clipboard:"),
00196 plainPage()
00197 );
00198 lyr->addWidget( m_infoLbl );
00199
00200 QWidget* page = new QFrame( plainPage(), "page" );
00201 QGridLayout *glyr= new QGridLayout( page, 4, 5, 0, KDialogBase::spacingHint(), "glyr");
00202 lyr->addWidget( page );
00203
00204
00205 m_delimiterWidget = new KexiCSVDelimiterWidget(true , page);
00206 glyr->addMultiCellWidget( m_delimiterWidget, 1, 2, 0, 0 );
00207
00208 QLabel *delimiterLabel = new QLabel(m_delimiterWidget, i18n("Delimiter:"), page);
00209 delimiterLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
00210 glyr->addMultiCellWidget( delimiterLabel, 0, 0, 0, 0 );
00211
00212
00213 m_formatComboText = i18n( "Format for column %1:" );
00214 m_formatCombo = new KComboBox(page, "m_formatCombo");
00215 m_formatCombo->insertItem(i18n("Text"));
00216 m_formatCombo->insertItem(i18n("Number"));
00217 m_formatCombo->insertItem(i18n("Date"));
00218 m_formatCombo->insertItem(i18n("Time"));
00219 m_formatCombo->insertItem(i18n("Date/Time"));
00220 glyr->addMultiCellWidget( m_formatCombo, 1, 1, 1, 1 );
00221
00222 m_formatLabel = new QLabel(m_formatCombo, "", page);
00223 m_formatLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
00224 glyr->addWidget( m_formatLabel, 0, 1 );
00225
00226 m_primaryKeyField = new QCheckBox( i18n( "Primary key" ), page, "m_primaryKeyField" );
00227 glyr->addWidget( m_primaryKeyField, 2, 1 );
00228 connect(m_primaryKeyField, SIGNAL(toggled(bool)), this, SLOT(slotPrimaryKeyFieldToggled(bool)));
00229
00230 m_comboQuote = new KexiCSVTextQuoteComboBox( page );
00231 glyr->addWidget( m_comboQuote, 1, 2 );
00232
00233 TextLabel2 = new QLabel( m_comboQuote, i18n( "Text quote:" ), page, "TextLabel2" );
00234 TextLabel2->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
00235 TextLabel2->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
00236 glyr->addWidget( TextLabel2, 0, 2 );
00237
00238 m_startAtLineSpinBox = new KIntSpinBox( page, "m_startAtLineSpinBox" );
00239 m_startAtLineSpinBox->setMinValue(1);
00240 m_startAtLineSpinBox->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00241 m_startAtLineSpinBox->setMinimumWidth(QFontMetrics(m_startAtLineSpinBox->font()).width("8888888"));
00242 glyr->addWidget( m_startAtLineSpinBox, 1, 3 );
00243
00244 m_startAtLineLabel = new QLabel( m_startAtLineSpinBox, "",
00245 page, "TextLabel3" );
00246 m_startAtLineLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
00247 m_startAtLineLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
00248 glyr->addWidget( m_startAtLineLabel, 0, 3 );
00249
00250 QSpacerItem* spacer_2 = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Preferred );
00251 glyr->addItem( spacer_2, 0, 4 );
00252
00253 m_ignoreDuplicates = new QCheckBox( page, "m_ignoreDuplicates" );
00254 m_ignoreDuplicates->setText( i18n( "Ignore duplicated delimiters" ) );
00255 glyr->addMultiCellWidget( m_ignoreDuplicates, 2, 2, 2, 4 );
00256
00257 m_1stRowForFieldNames = new QCheckBox( page, "m_1stRowForFieldNames" );
00258 m_1stRowForFieldNames->setText( i18n( "First row contains column names" ) );
00259 glyr->addMultiCellWidget( m_1stRowForFieldNames, 3, 3, 2, 4 );
00260
00261 m_table = new KexiCSVImportDialogTable( plainPage(), "m_table" );
00262 lyr->addWidget( m_table );
00263
00264 m_table->setSizePolicy( QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding, 1, 1) );
00265 m_table->setNumRows( 0 );
00266 m_table->setNumCols( 0 );
00267
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 m_dateRegExp1 = QRegExp("\\d{1,4}[/\\-\\.]\\d{1,2}[/\\-\\.]\\d{1,2}");
00292 m_dateRegExp2 = QRegExp("\\d{1,2}[/\\-\\.]\\d{1,2}[/\\-\\.]\\d{1,4}");
00293 m_timeRegExp1 = QRegExp("\\d{1,2}:\\d{1,2}:\\d{1,2}");
00294 m_timeRegExp2 = QRegExp("\\d{1,2}:\\d{1,2}");
00295 m_fpNumberRegExp = QRegExp("\\d*[,\\.]\\d+");
00296
00297 if (m_mode == File) {
00298 QStringList mimetypes( csvMimeTypes() );
00299 #ifdef Q_WS_WIN
00300
00301 QString recentDir = KGlobalSettings::documentPath();
00302 m_fname = QFileDialog::getOpenFileName(
00303 KFileDialog::getStartURL(":CSVImportExport", recentDir).path(),
00304 KexiUtils::fileDialogFilterStrings(mimetypes, false),
00305 page, "KexiCSVImportDialog", i18n("Open CSV Data File"));
00306 if ( !m_fname.isEmpty() ) {
00307
00308 KURL url;
00309 url.setPath( m_fname );
00310 if (url.isLocalFile())
00311 KRecentDirs::add(":CSVImportExport", url.directory());
00312 }
00313 #else
00314 m_fname = KFileDialog::getOpenFileName(":CSVImportExport", mimetypes.join(" "), this);
00315 #endif
00316
00317 if ( m_fname.isEmpty() )
00318 {
00319 actionButton( Ok )->setEnabled( false );
00320 m_cancelled = true;
00321 if (parentWidget())
00322 parentWidget()->raise();
00323 return;
00324 }
00325 }
00326 else if (m_mode == Clipboard) {
00327 QCString subtype("plain");
00328 m_data = QApplication::clipboard()->text(subtype, QClipboard::Clipboard);
00329
00330
00331
00332
00333
00334 }
00335 else {
00336 return;
00337 }
00338
00339 m_loadingProgressDlg = 0;
00340 m_importingProgressDlg = 0;
00341 if (m_mode == File) {
00342 m_loadingProgressDlg = new KProgressDialog(
00343 this, "m_loadingProgressDlg", i18n("Loading CSV Data"), i18n("Loading CSV Data from \"%1\"...")
00344 .arg(QDir::convertSeparators(m_fname)), true);
00345 m_loadingProgressDlg->progressBar()->setTotalSteps( m_maximumRowsForPreview+1 );
00346 m_loadingProgressDlg->show();
00347 }
00348
00349 if (m_mode==Clipboard) {
00350 m_infoLbl->setIcon("editpaste");
00351 }
00352 updateRowCountInfo();
00353
00354 m_table->setSelectionMode(QTable::NoSelection);
00355
00356 connect(m_formatCombo, SIGNAL(activated(int)),
00357 this, SLOT(formatChanged(int)));
00358 connect(m_delimiterWidget, SIGNAL(delimiterChanged(const QString&)),
00359 this, SLOT(delimiterChanged(const QString&)));
00360 connect(m_startAtLineSpinBox, SIGNAL(valueChanged ( int )),
00361 this, SLOT(startlineSelected(int)));
00362 connect(m_comboQuote, SIGNAL(activated(int)),
00363 this, SLOT(textquoteSelected(int)));
00364 connect(m_table, SIGNAL(currentChanged(int, int)),
00365 this, SLOT(currentCellChanged(int, int)));
00366 connect(m_table, SIGNAL(valueChanged(int,int)),
00367 this, SLOT(cellValueChanged(int,int)));
00368 connect(m_ignoreDuplicates, SIGNAL(stateChanged(int)),
00369 this, SLOT(ignoreDuplicatesChanged(int)));
00370 connect(m_1stRowForFieldNames, SIGNAL(stateChanged(int)),
00371 this, SLOT(slot1stRowForFieldNamesChanged(int)));
00372
00373 connect(this, SIGNAL(user1Clicked()), this, SLOT(optionsButtonClicked()));
00374
00375 installRecursiveEventFilter(this, this);
00376
00377 initLater();
00378 }
00379
00380 KexiCSVImportDialog::~KexiCSVImportDialog()
00381 {
00382 delete m_file;
00383 }
00384
00385 void KexiCSVImportDialog::initLater()
00386 {
00387 if (!openData())
00388 return;
00389
00390 QChar detectedDelimiter;
00391 if (m_mode==File) {
00392
00393
00394 for (uint i=0; i < QMIN(4096, m_data.length()); i++) {
00395 const QChar c(m_data[i]);
00396 if (c=='\t') {
00397 detectedDelimiter = c;
00398 break;
00399 }
00400 else if (c==',' && detectedDelimiter!='\t') {
00401 detectedDelimiter = c;
00402 }
00403 else if (c==';' && detectedDelimiter!='\t' && detectedDelimiter!=',') {
00404 detectedDelimiter = c;
00405 }
00406 }
00407 }
00408 if (detectedDelimiter.isNull())
00409 detectedDelimiter = m_mode==File
00410 ? KEXICSV_DEFAULT_FILE_DELIMITER[0] : KEXICSV_DEFAULT_CLIPBOARD_DELIMITER[0];
00411
00412 m_delimiterWidget->setDelimiter(QString(detectedDelimiter));
00413
00414 m_columnsAdjusted = false;
00415 fillTable();
00416 delete m_loadingProgressDlg;
00417 m_loadingProgressDlg = 0;
00418 if (m_dialogCancelled) {
00419
00420
00421 QTimer::singleShot(0, this, SLOT(reject()));
00422 return;
00423 }
00424
00425 currentCellChanged(0, 0);
00426
00427
00428 adjustSize();
00429 KDialog::centerOnScreen( this );
00430
00431 if (m_loadingProgressDlg)
00432 m_loadingProgressDlg->hide();
00433 show();
00434 m_table->setFocus();
00435 }
00436
00437 bool KexiCSVImportDialog::openData()
00438 {
00439 if (m_mode!=File)
00440 return true;
00441
00442 delete m_inputStream;
00443 m_inputStream = 0;
00444 if (m_file) {
00445 m_file->close();
00446 delete m_file;
00447 }
00448 m_file = new QFile(m_fname);
00449 if (!m_file->open(IO_ReadOnly))
00450 {
00451 m_file->close();
00452 delete m_file;
00453 m_file = 0;
00454 KMessageBox::sorry( this, i18n("Cannot open input file <nobr>\"%1\"</nobr>.")
00455 .arg(QDir::convertSeparators(m_fname)) );
00456 actionButton( Ok )->setEnabled( false );
00457 m_cancelled = true;
00458 if (parentWidget())
00459 parentWidget()->raise();
00460 return false;
00461 }
00462 return true;
00463 }
00464
00465 bool KexiCSVImportDialog::cancelled() const
00466 {
00467 return m_cancelled;
00468 }
00469
00470 void KexiCSVImportDialog::fillTable()
00471 {
00472 KexiUtils::WaitCursor wc(true);
00473 repaint();
00474 m_blockUserEvents = true;
00475 QPushButton *pb = actionButton(KDialogBase::Cancel);
00476 if (pb)
00477 pb->setEnabled(true);
00478 KexiUtils::WaitCursor wait;
00479
00480 if (m_table->numRows()>0)
00481 m_table->setCurrentCell(0,0);
00482
00483 int row, column, maxColumn;
00484 QString field = QString::null;
00485
00486 for (row = 0; row < m_table->numRows(); ++row)
00487 for (column = 0; column < m_table->numCols(); ++column)
00488 m_table->clearCell(row, column);
00489
00490 m_detectedTypes.clear();
00491 m_detectedTypes.resize(1024, _NO_TYPE_YET);
00492 m_uniquenessTest.clear();
00493 m_uniquenessTest.resize(1024);
00494 m_1stRowForFieldNamesDetected = true;
00495
00496 if (true != loadRows(field, row, column, maxColumn, true))
00497 return;
00498
00499 m_1stRowForFieldNamesDetected = false;
00500
00501
00502 if (field.length() > 0)
00503 {
00504 setText(row - m_startline, column, field, true);
00505 ++row;
00506 field = QString::null;
00507 }
00508
00509 adjustRows( row - m_startline - (m_1stRowForFieldNames->isChecked()?1:0) );
00510
00511 maxColumn = QMAX( maxColumn, column );
00512 m_table->setNumCols(maxColumn);
00513
00514 for (column = 0; column < m_table->numCols(); ++column)
00515 {
00516
00517
00518
00519
00520
00521 updateColumnText(column);
00522 if (!m_columnsAdjusted)
00523 m_table->adjustColumn(column);
00524 }
00525 m_columnsAdjusted = true;
00526
00527 if (m_primaryKeyColumn>=0 && m_primaryKeyColumn<m_table->numCols()) {
00528 if (_NUMBER_TYPE != m_detectedTypes[ m_primaryKeyColumn ]) {
00529 m_primaryKeyColumn = -1;
00530 }
00531 }
00532
00533 m_prevSelectedCol = -1;
00534 m_table->setCurrentCell(0,0);
00535 currentCellChanged(0, 0);
00536 if (m_primaryKeyColumn != -1)
00537 m_table->setPixmap(0, m_primaryKeyColumn, m_pkIcon);
00538
00539 const int count = QMAX(0, m_table->numRows()-1+m_startline);
00540 const bool allRowsLoaded = count < m_maximumRowsForPreview;
00541 if (allRowsLoaded) {
00542 m_startAtLineSpinBox->setMaxValue(count);
00543 m_startAtLineSpinBox->setValue(m_startline+1);
00544 }
00545 m_startAtLineLabel->setText(i18n( "Start at line%1:").arg(
00546 allRowsLoaded ? QString(" (1-%1)").arg(count)
00547 : QString::null
00548 ));
00549
00550 m_blockUserEvents = false;
00551 repaint();
00552 m_table->verticalScrollBar()->repaint();
00553 m_table->horizontalScrollBar()->repaint();
00554 }
00555
00556 tristate KexiCSVImportDialog::loadRows(QString &field, int &row, int &column, int &maxColumn,
00557 bool inGUI)
00558 {
00559 enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
00560 S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
00561 const QChar delimiter(m_delimiterWidget->delimiter()[0]);
00562 field = QString::null;
00563 const bool ignoreDups = m_ignoreDuplicates->isChecked();
00564 bool lastCharDelimiter = false;
00565 bool nextRow = false;
00566 row = column = 1;
00567 maxColumn = 0;
00568 QChar x;
00569 delete m_inputStream;
00570 if ( m_mode == Clipboard ) {
00571 m_inputStream = new QTextStream(m_data, IO_ReadOnly);
00572 }
00573 else {
00574 m_file->at(0);
00575 m_inputStream = new QTextStream(m_file);
00576 if (m_encoding != QString::fromLatin1(KGlobal::locale()->encoding())) {
00577 QTextCodec *codec = KGlobal::charsets()->codecForName(m_encoding);
00578 if (codec)
00579 m_inputStream->setCodec(codec);
00580 }
00581 }
00582 int progressStep = 0;
00583 if (m_importingProgressDlg)
00584 progressStep = QMAX( 1, m_importingProgressDlg->progressBar()->totalSteps()/200 );
00585 int offset = 0;
00586 for (;!m_inputStream->atEnd(); offset++)
00587 {
00588 if (column >= m_maximumRowsForPreview)
00589 return true;
00590
00591 if (m_importingProgressDlg && ((offset % progressStep) < 5)) {
00592
00593 m_importingProgressDlg->progressBar()->setValue(offset);
00594 qApp->processEvents();
00595 if (m_importingProgressDlg->wasCancelled()) {
00596 delete m_importingProgressDlg;
00597 m_importingProgressDlg = 0;
00598 return ::cancelled;
00599 }
00600 }
00601
00602 (*m_inputStream) >> x;
00603
00604 if (x == '\r') {
00605 continue;
00606 }
00607
00608 switch (state)
00609 {
00610 case S_START :
00611 if (x == m_textquote)
00612 {
00613 state = S_QUOTED_FIELD;
00614 }
00615 else if (x == delimiter)
00616 {
00617 setText(row - m_startline, column, field, inGUI);
00618 field = QString::null;
00619 if ((ignoreDups == false) || (lastCharDelimiter == false))
00620 ++column;
00621 lastCharDelimiter = true;
00622 }
00623 else if (x == '\n')
00624 {
00625 if (!inGUI) {
00626
00627 for (int additionalColumn = column; additionalColumn <= maxColumn; additionalColumn++) {
00628 setText(row - m_startline, additionalColumn, QString::null, inGUI);
00629 }
00630 }
00631 nextRow = true;
00632 maxColumn = QMAX( maxColumn, column );
00633 column = 1;
00634 }
00635 else
00636 {
00637 field += x;
00638 state = S_MAYBE_NORMAL_FIELD;
00639 }
00640 break;
00641 case S_QUOTED_FIELD :
00642 if (x == m_textquote)
00643 {
00644 state = S_MAYBE_END_OF_QUOTED_FIELD;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 else
00666 {
00667 field += x;
00668 }
00669 break;
00670 case S_MAYBE_END_OF_QUOTED_FIELD :
00671 if (x == m_textquote)
00672 {
00673 field += x;
00674 state = S_QUOTED_FIELD;
00675 }
00676 else if (x == delimiter || x == '\n')
00677 {
00678 setText(row - m_startline, column, field, inGUI);
00679 field = QString::null;
00680 if (x == '\n')
00681 {
00682 nextRow = true;
00683 maxColumn = QMAX( maxColumn, column );
00684 column = 1;
00685 }
00686 else
00687 {
00688 if ((ignoreDups == false) || (lastCharDelimiter == false))
00689 ++column;
00690 lastCharDelimiter = true;
00691 }
00692 state = S_START;
00693 }
00694 else
00695 {
00696 state = S_END_OF_QUOTED_FIELD;
00697 }
00698 break;
00699 case S_END_OF_QUOTED_FIELD :
00700 if (x == delimiter || x == '\n')
00701 {
00702 setText(row - m_startline, column, field, inGUI);
00703 field = QString::null;
00704 if (x == '\n')
00705 {
00706 nextRow = true;
00707 maxColumn = QMAX( maxColumn, column );
00708 column = 1;
00709 }
00710 else
00711 {
00712 if ((ignoreDups == false) || (lastCharDelimiter == false))
00713 ++column;
00714 lastCharDelimiter = true;
00715 }
00716 state = S_START;
00717 }
00718 else
00719 {
00720 state = S_END_OF_QUOTED_FIELD;
00721 }
00722 break;
00723 case S_MAYBE_NORMAL_FIELD :
00724 if (x == m_textquote)
00725 {
00726 field = QString::null;
00727 state = S_QUOTED_FIELD;
00728 break;
00729 }
00730 case S_NORMAL_FIELD :
00731 if (x == delimiter || x == '\n')
00732 {
00733 setText(row - m_startline, column, field, inGUI);
00734 field = QString::null;
00735 if (x == '\n')
00736 {
00737 nextRow = true;
00738 maxColumn = QMAX( maxColumn, column );
00739 column = 1;
00740 }
00741 else
00742 {
00743 if ((ignoreDups == false) || (lastCharDelimiter == false))
00744 ++column;
00745 lastCharDelimiter = true;
00746 }
00747 state = S_START;
00748 }
00749 else
00750 {
00751 field += x;
00752 }
00753 }
00754 if (x != delimiter)
00755 lastCharDelimiter = false;
00756
00757 if (nextRow) {
00758 nextRow = false;
00759 if (!inGUI && row==1 && m_1stRowForFieldNames->isChecked()) {
00760
00761 m_importingStatement->clearArguments();
00762 }
00763 else if (!saveRow(inGUI))
00764 return false;
00765 ++row;
00766 }
00767
00768 if (m_firstFillTableCall && row==2
00769 && !m_1stRowForFieldNames->isChecked() && m_1stRowForFieldNamesDetected)
00770 {
00771
00772 m_1stRowForFieldNamesDetected = false;
00773 m_table->setNumRows( 0 );
00774 m_firstFillTableCall = false;
00775 m_1stRowForFieldNames->setChecked(true);
00776
00777 m_blockUserEvents = false;
00778 repaint();
00779 return false;
00780 }
00781
00782 if (!m_importingProgressDlg && row % 20 == 0) {
00783 qApp->processEvents();
00784
00785 if (!m_firstFillTableCall && m_loadingProgressDlg && m_loadingProgressDlg->wasCancelled()) {
00786 delete m_loadingProgressDlg;
00787 m_loadingProgressDlg = 0;
00788 m_dialogCancelled = true;
00789 reject();
00790 return false;
00791 }
00792 }
00793
00794 if (!m_firstFillTableCall && m_loadingProgressDlg) {
00795 m_loadingProgressDlg->progressBar()->setValue(QMIN(m_maximumRowsForPreview, row));
00796 }
00797
00798 if ( inGUI && row > (m_maximumRowsForPreview + (m_1stRowForFieldNamesDetected?1:0)) ) {
00799 kexipluginsdbg << "KexiCSVImportDialog::fillTable() loading stopped at row #"
00800 << m_maximumRowsForPreview << endl;
00801 break;
00802 }
00803 }
00804 return true;
00805 }
00806
00807 void KexiCSVImportDialog::updateColumnText(int col)
00808 {
00809 QString colName;
00810 if (col<(int)m_columnNames.count() && (m_1stRowForFieldNames->isChecked() || m_changedColumnNames[col]))
00811 colName = m_columnNames[ col ];
00812 if (colName.isEmpty()) {
00813 colName = i18n("Column %1").arg(col+1);
00814 m_changedColumnNames[ col ] = false;
00815 }
00816 int detectedType = m_detectedTypes[col];
00817 if (detectedType==_FP_NUMBER_TYPE)
00818 detectedType=_NUMBER_TYPE;
00819 else if (detectedType==_NO_TYPE_YET) {
00820 m_detectedTypes[col]=_TEXT_TYPE;
00821 detectedType=_TEXT_TYPE;
00822 }
00823 m_table->horizontalHeader()->setLabel(col,
00824 i18n("Column %1").arg(col+1) + " \n(" + m_typeNames[ detectedType ] + ") ");
00825 m_table->setText(0, col, colName);
00826 m_table->horizontalHeader()->adjustHeaderSize();
00827
00828
00829 QValueList<int> *list = m_uniquenessTest[col];
00830 if (m_primaryKeyColumn==-1 && list && !list->isEmpty()) {
00831 qHeapSort(*list);
00832 QValueList<int>::ConstIterator it=list->constBegin();
00833 int prevValue = *it;
00834 ++it;
00835 for(; it!=list->constEnd() && prevValue!=(*it); ++it)
00836 prevValue=(*it);
00837 if (it!=list->constEnd()) {
00838
00839 list->clear();
00840 }
00841 else {
00842
00843 if (-1==m_primaryKeyColumn) {
00844 m_primaryKeyColumn=col;
00845 }
00846 }
00847 }
00848 if (list)
00849 list->clear();
00850 }
00851
00852 void KexiCSVImportDialog::detectTypeAndUniqueness(int row, int col, const QString& text)
00853 {
00854 int intValue;
00855 const int type = m_detectedTypes[col];
00856 if (row==1 || type!=_TEXT_TYPE) {
00857 bool found = false;
00858 if (text.isEmpty() && type==_NO_TYPE_YET)
00859 found = true;
00860
00861
00862 if (!found && (row==1 || type==_NUMBER_TYPE || type==_NO_TYPE_YET)) {
00863 bool ok = text.isEmpty();
00864 if (!ok)
00865 intValue = text.toInt(&ok);
00866 if (ok && (row==1 || type==_NO_TYPE_YET)) {
00867 m_detectedTypes[col]=_NUMBER_TYPE;
00868 found = true;
00869 }
00870 }
00871
00872 if (!found && (row==1 || type==_FP_NUMBER_TYPE || type==_NO_TYPE_YET)) {
00873 bool ok = text.isEmpty() || m_fpNumberRegExp.exactMatch(text);
00874 if (!ok)
00875 text.toInt(&ok);
00876 if (ok && (row==1 || type==_NO_TYPE_YET)) {
00877 m_detectedTypes[col]=_FP_NUMBER_TYPE;
00878 found = true;
00879 }
00880 }
00881
00882 if (!found && (row==1 || type==_DATE_TYPE || type==_NO_TYPE_YET)) {
00883 if ((row==1 || type==_NO_TYPE_YET)
00884 && (text.isEmpty() || m_dateRegExp1.exactMatch(text) || m_dateRegExp2.exactMatch(text)))
00885 {
00886 m_detectedTypes[col]=_DATE_TYPE;
00887 found = true;
00888 }
00889 }
00890
00891 if (!found && (row==1 || type==_TIME_TYPE || type==_NO_TYPE_YET)) {
00892 if ((row==1 || type==_NO_TYPE_YET)
00893 && (text.isEmpty() || m_timeRegExp1.exactMatch(text) || m_timeRegExp2.exactMatch(text)))
00894 {
00895 m_detectedTypes[col]=_TIME_TYPE;
00896 found = true;
00897 }
00898 }
00899
00900 if (!found && (row==1 || type==_TIME_TYPE || type==_NO_TYPE_YET)) {
00901 if (row==1 || type==_NO_TYPE_YET) {
00902 bool detected = text.isEmpty();
00903 if (!detected) {
00904 const QStringList dateTimeList( QStringList::split(" ", text) );
00905 bool ok = dateTimeList.count()>=2;
00908 if (ok) {
00909
00910 QString datePart( dateTimeList[0].stripWhiteSpace() );
00911 QString timePart( dateTimeList[1].stripWhiteSpace() );
00912 ok = (m_dateRegExp1.exactMatch(datePart) || m_dateRegExp2.exactMatch(datePart))
00913 && (m_timeRegExp1.exactMatch(timePart) || m_timeRegExp2.exactMatch(timePart));
00914 }
00915 detected = ok;
00916 }
00917 if (detected) {
00918 m_detectedTypes[col]=_DATETIME_TYPE;
00919 found = true;
00920 }
00921 }
00922 }
00923 if (!found && type==_NO_TYPE_YET && !text.isEmpty()) {
00924
00925 m_detectedTypes[col]=_TEXT_TYPE;
00926 found = true;
00927 }
00928
00929 }
00930
00931 QValueList<int> *list = m_uniquenessTest[col];
00932 if (row==1 && (!list || !list->isEmpty()) && !text.isEmpty() && _NUMBER_TYPE == m_detectedTypes[col]) {
00933 if (!list) {
00934 list = new QValueList<int>();
00935 m_uniquenessTest.insert(col, list);
00936 }
00937 list->append( intValue );
00938 }
00939 else {
00940
00941 if (list && !list->isEmpty())
00942 list->clear();
00943 }
00944 }
00945
00946 void KexiCSVImportDialog::setText(int row, int col, const QString& text, bool inGUI)
00947 {
00948 if (!inGUI) {
00949
00950 if (col==1) {
00951 m_importingStatement->clearArguments();
00952 if (m_implicitPrimaryKeyAdded)
00953 *m_importingStatement << QVariant();
00954 }
00955 const int detectedType = m_detectedTypes[col-1];
00956 if (detectedType==_NUMBER_TYPE) {
00957 *m_importingStatement << ( text.isEmpty() ? QVariant() : text.toInt() );
00959 }
00960 else if (detectedType==_FP_NUMBER_TYPE) {
00961 *m_importingStatement << ( text.isEmpty() ? QVariant() : text.toDouble() );
00962 }
00963 else if (detectedType==_DATE_TYPE) {
00964 QDate date( QDate::fromString(text, Qt::ISODate) );
00965 if (!date.isValid() && m_dateRegExp2.exactMatch(text))
00966 date = QDate(text.mid(6,4).toInt(), text.mid(3,2).toInt(), text.left(2).toInt());
00967 *m_importingStatement << date;
00968 }
00969 else if (detectedType==_TIME_TYPE) {
00970 QTime time( QTime::fromString(text, Qt::ISODate) );
00971 if (!time.isValid() && m_timeRegExp2.exactMatch(text))
00972 time = QTime(text.left(2).toInt(), text.mid(3,2).toInt(), text.mid(6,2).toInt());
00973 *m_importingStatement << time;
00974 }
00975 else if (detectedType==_DATETIME_TYPE) {
00976 const QStringList dateTimeList( QStringList::split(" ", text) );
00979 if (dateTimeList.count()>=2) {
00980
00981 QString datePart( dateTimeList[0].stripWhiteSpace() );
00982 QString timePart( dateTimeList[1].stripWhiteSpace() );
00983 QDateTime dateTime;
00984 dateTime.setDate( QDate::fromString(datePart, Qt::ISODate) );
00985 if (!dateTime.date().isValid() && m_dateRegExp2.exactMatch(datePart))
00986 dateTime.setDate( QDate(datePart.mid(6,4).toInt(),
00987 datePart.mid(3,2).toInt(), datePart.left(2).toInt()) );
00988 dateTime.setTime( QTime::fromString(timePart, Qt::ISODate) );
00989 if (!dateTime.time().isValid() && m_timeRegExp2.exactMatch(timePart))
00990 dateTime.setTime( QTime(timePart.left(2).toInt(),
00991 timePart.mid(3,2).toInt(), timePart.mid(6,2).toInt()) );
00992 *m_importingStatement << dateTime;
00993 }
00994 }
00995 else
00996 *m_importingStatement << text;
00997 return;
00998 }
00999
01000 if (m_table->numCols() < col) {
01001 m_table->setNumCols(col);
01002 if ((int)m_columnNames.size() < m_table->numCols()) {
01003 m_columnNames.resize(m_table->numCols()+10);
01004 m_changedColumnNames.resize(m_table->numCols()+10);
01005 }
01006 }
01007
01008 if (m_1stRowForFieldNames->isChecked()) {
01009 if ((row+m_startline)==1) {
01010 if ((col-1) < (int)m_changedColumnNames.size() && false==m_changedColumnNames[col-1]) {
01011
01012
01013 QString colName(text.simplifyWhiteSpace());
01014 if (!colName.isEmpty()) {
01015 if (colName.left(1)>="0" && colName.left(1)<="9")
01016 colName.prepend(i18n("Column")+" ");
01017 m_columnNames[ col-1 ] = colName;
01018 }
01019 }
01020 return;
01021 }
01022 }
01023 else {
01024 if ((row+m_startline)==1) {
01025 if (m_1stRowForFieldNamesDetected && !m_1stRowForFieldNames->isChecked()) {
01026 QString f( text.simplifyWhiteSpace() );
01027 if (f.isEmpty() || !f[0].isLetter())
01028 m_1stRowForFieldNamesDetected = false;
01029 }
01030 }
01031 row++;
01032 }
01033
01034 if (row < 2)
01035 return;
01036
01037 if (m_table->numRows() < row) {
01038
01039 m_table->setNumRows(row+100);
01040
01041
01042 m_table->verticalHeader()->setLabel(0, i18n("Column name")+" ");
01043 m_adjustRows=1;
01044 }
01045
01046 m_table->setText(row - 1, col - 1, text);
01047 m_table->verticalHeader()->setLabel(row-1, QString::number(row-1));
01048
01049 detectTypeAndUniqueness(row-1, col-1, text);
01050 }
01051
01052 bool KexiCSVImportDialog::saveRow(bool inGUI)
01053 {
01054 if (inGUI) {
01055
01056 return true;
01057 }
01058
01059 bool res = m_importingStatement->execute();
01060
01061 m_importingStatement->clearArguments();
01062 return res;
01063
01064 }
01065
01066 void KexiCSVImportDialog::adjustRows(int iRows)
01067 {
01068 if (m_adjustRows)
01069 {
01070 m_table->setNumRows( iRows );
01071 m_adjustRows=0;
01072 for (int i = 0; i<iRows; i++)
01073 m_table->adjustRow(i);
01074 }
01075 }
01076
01077 void KexiCSVImportDialog::formatChanged(int id)
01078 {
01079 if (id==_PK_FLAG) {
01080 if (m_primaryKeyColumn>=0 && m_primaryKeyColumn<m_table->numCols()) {
01081 m_table->setPixmap(0, m_primaryKeyColumn, QPixmap());
01082 }
01083 if (m_primaryKeyField->isChecked()) {
01084 m_primaryKeyColumn = m_table->currentColumn();
01085 m_table->setPixmap(0, m_primaryKeyColumn, m_pkIcon);
01086 }
01087 else
01088 m_primaryKeyColumn = -1;
01089 return;
01090 }
01091 else {
01092 m_detectedTypes[m_table->currentColumn()]=id;
01093 m_primaryKeyField->setEnabled( _NUMBER_TYPE == id );
01094 m_primaryKeyField->setChecked( m_primaryKeyColumn == m_table->currentColumn() && m_primaryKeyField->isEnabled() );
01095 }
01096 updateColumnText(m_table->currentColumn());
01097 }
01098
01099 void KexiCSVImportDialog::delimiterChanged(const QString& delimiter)
01100 {
01101 Q_UNUSED(delimiter);
01102 m_columnsAdjusted = false;
01103
01104 QTimer::singleShot(10, this, SLOT(fillTable()));
01105 }
01106
01107 void KexiCSVImportDialog::textquoteSelected(int)
01108 {
01109 const QString tq(m_comboQuote->textQuote());
01110 if (tq.isEmpty())
01111 m_textquote = 0;
01112 else
01113 m_textquote = tq[0];
01114
01115
01116 QTimer::singleShot(10, this, SLOT(fillTable()));
01117 }
01118
01119 void KexiCSVImportDialog::startlineSelected(int startline)
01120 {
01121
01122 if (m_startline == (startline-1))
01123 return;
01124 m_startline = startline-1;
01125 m_adjustRows=1;
01126 fillTable();
01127 m_table->setFocus();
01128 }
01129
01130 void KexiCSVImportDialog::currentCellChanged(int, int col)
01131 {
01132 if (m_prevSelectedCol==col)
01133 return;
01134 m_prevSelectedCol = col;
01135 int type = m_detectedTypes[col];
01136 if (type==_FP_NUMBER_TYPE)
01137 type=_NUMBER_TYPE;
01138
01139 m_formatCombo->setCurrentItem( type );
01140 m_formatLabel->setText( m_formatComboText.arg(col+1) );
01141 m_primaryKeyField->setEnabled( _NUMBER_TYPE == m_detectedTypes[col]);
01142 m_primaryKeyField->blockSignals(true);
01143 m_primaryKeyField->setChecked( m_primaryKeyColumn == col );
01144 m_primaryKeyField->blockSignals(false);
01145 }
01146
01147 void KexiCSVImportDialog::cellValueChanged(int row,int col)
01148 {
01149 if (row==0) {
01150 m_columnNames[ col ] = m_table->text(row, col);
01151 m_changedColumnNames.setBit( col );
01152 }
01153 }
01154
01155 void KexiCSVImportDialog::accept()
01156 {
01158
01159 KexiGUIMessageHandler msg;
01160
01161 const uint numRows( m_table->numRows() );
01162 if (numRows == 0)
01163 return;
01164
01165 if (numRows == 1) {
01166 if (KMessageBox::No == KMessageBox::questionYesNo(this,
01167 i18n("Data set contains no rows. Do you want to import empty table?")))
01168 return;
01169 }
01170
01171 KexiProject* project = m_mainWin->project();
01172 if (!project) {
01173 msg.showErrorMessage(i18n("No project available."));
01174 return;
01175 }
01176 m_conn = project->dbConnection();
01177 if (!m_conn) {
01178 msg.showErrorMessage(i18n("No database connection available."));
01179 return;
01180 }
01181 KexiPart::Part *part = Kexi::partManager().partForMimeType("kexi/table");
01182 if (!part) {
01183 msg.showErrorMessage(&Kexi::partManager());
01184 return;
01185 }
01186
01187
01188 QString suggestedName;
01189 if (m_mode==File) {
01190 suggestedName = KURL::fromPathOrURL(m_fname).fileName();
01191
01192 if (!suggestedName.isEmpty()) {
01193 const int idx = suggestedName.findRev(".");
01194 if (idx!=-1)
01195 suggestedName = suggestedName.mid(0, idx ).simplifyWhiteSpace();
01196 }
01197 }
01198
01199
01200 KexiPart::Item* partItemForSavedTable = project->createPartItem(part->info(), suggestedName);
01201 if (!partItemForSavedTable) {
01202
01203 return;
01204 }
01205
01206 #define _ERR \
01207 { project->deleteUnstoredItem(partItemForSavedTable); \
01208 m_conn = 0; \
01209 delete m_destinationTableSchema; \
01210 m_destinationTableSchema = 0; \
01211 return; }
01212
01213
01214
01215 bool allowOverwriting = true;
01216 tristate res = m_mainWin->getNewObjectInfo( partItemForSavedTable, part, allowOverwriting );
01217 if (~res || !res) {
01219 _ERR;
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229 m_destinationTableSchema = new KexiDB::TableSchema(partItemForSavedTable->name());
01230 m_destinationTableSchema->setCaption( partItemForSavedTable->caption() );
01231 m_destinationTableSchema->setDescription( partItemForSavedTable->description() );
01232 const uint numCols( m_table->numCols() );
01233
01234 m_implicitPrimaryKeyAdded = false;
01235
01236 int msgboxResult;
01237 if (m_primaryKeyColumn==-1
01238 && KMessageBox::No != (msgboxResult = KMessageBox::questionYesNoCancel(this,
01239 i18n("No Primary Key (autonumber) has been defined.\n"
01240 "Should it be automatically defined on import (recommended)?\n\n"
01241 "Note: An imported table without a Primary Key may not be editable (depending on database type)."),
01242 QString::null, KGuiItem(i18n("Add Database Primary Key to a Table", "Add Primary Key"), "key"),
01243 KGuiItem(i18n("Do Not Add Database Primary Key to a Table", "Do Not Add")))))
01244 {
01245 if (msgboxResult == KMessageBox::Cancel)
01246 _ERR;
01247
01248
01250 m_implicitPrimaryKeyAdded = true;
01251
01252 QString fieldName("id");
01253 QString fieldCaption("Id");
01254
01255 QStringList colnames;
01256 for (uint col = 0; col < numCols; col++)
01257 colnames.append( m_table->text(0, col).lower().simplifyWhiteSpace() );
01258
01259 if (colnames.find(fieldName)!=colnames.end()) {
01260 int num = 1;
01261 while (colnames.find(fieldName+QString::number(num))!=colnames.end())
01262 num++;
01263 fieldName += QString::number(num);
01264 fieldCaption += QString::number(num);
01265 }
01266 KexiDB::Field *field = new KexiDB::Field(
01267 fieldName,
01268 KexiDB::Field::Integer,
01269 KexiDB::Field::NoConstraints,
01270 KexiDB::Field::NoOptions,
01271 0,0,
01272 QVariant(),
01273 fieldCaption
01274 );
01275 field->setPrimaryKey(true);
01276 field->setAutoIncrement(true);
01277 m_destinationTableSchema->addField( field );
01278 }
01279
01280 for (uint col = 0; col < numCols; col++) {
01281 QString fieldCaption( m_table->text(0, col).simplifyWhiteSpace() );
01282 QString fieldName( KexiUtils::string2Identifier( fieldCaption ) );
01283 if (m_destinationTableSchema->field(fieldName)) {
01284 QString fixedFieldName;
01285 uint i = 2;
01286 do {
01287 fixedFieldName = fieldName + "_" + QString::number(i);
01288 if (!m_destinationTableSchema->field(fixedFieldName))
01289 break;
01290 i++;
01291 } while (true);
01292 fieldName = fixedFieldName;
01293 fieldCaption += (" " + QString::number(i));
01294 }
01295 const int detectedType = m_detectedTypes[col];
01296 KexiDB::Field::Type fieldType;
01297 if (detectedType==_DATE_TYPE)
01298 fieldType = KexiDB::Field::Date;
01299 if (detectedType==_TIME_TYPE)
01300 fieldType = KexiDB::Field::Time;
01301 if (detectedType==_DATETIME_TYPE)
01302 fieldType = KexiDB::Field::DateTime;
01303 else if (detectedType==_NUMBER_TYPE)
01304 fieldType = KexiDB::Field::Integer;
01305 else if (detectedType==_FP_NUMBER_TYPE)
01306 fieldType = KexiDB::Field::Double;
01308 else
01309 fieldType = KexiDB::Field::Text;
01311
01312 KexiDB::Field *field = new KexiDB::Field(
01313 fieldName,
01314 fieldType,
01315 KexiDB::Field::NoConstraints,
01316 KexiDB::Field::NoOptions,
01317 0,0,
01318 QVariant(),
01319 fieldCaption
01320 );
01321
01322 if ((int)col == m_primaryKeyColumn) {
01323 field->setPrimaryKey(true);
01324 field->setAutoIncrement(true);
01325 }
01326 m_destinationTableSchema->addField( field );
01327 }
01328
01329 KexiDB::Transaction transaction = m_conn->beginTransaction();
01330 if (transaction.isNull()) {
01331 msg.showErrorMessage(m_conn);
01332 _ERR;
01333 }
01334 KexiDB::TransactionGuard tg(transaction);
01335
01336
01337 if (!m_conn->createTable(m_destinationTableSchema, allowOverwriting)) {
01338 msg.showErrorMessage(m_conn);
01339 _ERR;
01340 }
01341
01342 #define _DROP_DEST_TABLE_AND_RETURN \
01343 { \
01344 if (m_importingProgressDlg) \
01345 m_importingProgressDlg->hide(); \
01346 project->deleteUnstoredItem(partItemForSavedTable); \
01347 m_conn->dropTable(m_destinationTableSchema); \
01348 m_destinationTableSchema = 0; \
01349 m_conn = 0; \
01350 return; \
01351 }
01352
01353 m_importingStatement = m_conn->prepareStatement(
01354 KexiDB::PreparedStatement::InsertStatement, *m_destinationTableSchema);
01355 if (!m_importingStatement) {
01356 msg.showErrorMessage(m_conn);
01357 _DROP_DEST_TABLE_AND_RETURN;
01358 }
01359
01360 if (m_file) {
01361 if (!m_importingProgressDlg) {
01362 m_importingProgressDlg = new KProgressDialog( this, "m_importingProgressDlg",
01363 i18n("Importing CSV Data"), QString::null, true );
01364 }
01365 m_importingProgressDlg->setLabel(
01366 i18n("Importing CSV Data from <nobr>\"%1\"</nobr> into \"%2\" table...")
01367 .arg(QDir::convertSeparators(m_fname)).arg(m_destinationTableSchema->name()) );
01368 m_importingProgressDlg->progressBar()->setTotalSteps( QFileInfo(*m_file).size() );
01369 m_importingProgressDlg->show();
01370 }
01371
01372 int row, column, maxColumn;
01373 QString field = QString::null;
01374
01375
01376 res = loadRows(field, row, column, maxColumn, false );
01377
01378 delete m_importingProgressDlg;
01379 m_importingProgressDlg = 0;
01380 if (true != res) {
01381
01382 if (!res)
01383 msg.showErrorMessage(m_conn);
01384 _DROP_DEST_TABLE_AND_RETURN;
01385 }
01386
01387
01388 if (field.length() > 0)
01389 {
01390 setText(row - m_startline, column, field, false );
01391
01392 for (int additionalColumn = column; additionalColumn <= maxColumn; additionalColumn++) {
01393 setText(row - m_startline, additionalColumn, QString::null, false );
01394 }
01395 if (!saveRow(false )) {
01396 msg.showErrorMessage(m_conn);
01397 _DROP_DEST_TABLE_AND_RETURN;
01398 }
01399 ++row;
01400 field = QString::null;
01401 }
01402
01403 if (!tg.commit()) {
01404 msg.showErrorMessage(m_conn);
01405 _DROP_DEST_TABLE_AND_RETURN;
01406 }
01407
01408
01409 partItemForSavedTable->setIdentifier( m_destinationTableSchema->id() );
01410 project->addStoredItem( part->info(), partItemForSavedTable );
01411
01412 QDialog::accept();
01413 KMessageBox::information(this, i18n("Data has been successfully imported to table \"%1\".")
01414 .arg(m_destinationTableSchema->name()));
01415 parentWidget()->raise();
01416 m_conn = 0;
01417 }
01418
01419 int KexiCSVImportDialog::getHeader(int col)
01420 {
01421 QString header = m_table->horizontalHeader()->label(col);
01422
01423 if (header == i18n("Text type for column", "Text"))
01424 return TEXT;
01425 else if (header == i18n("Numeric type for column", "Number"))
01426 return NUMBER;
01427 else if (header == i18n("Currency type for column", "Currency"))
01428 return CURRENCY;
01429 else
01430 return DATE;
01431 }
01432
01433 QString KexiCSVImportDialog::getText(int row, int col)
01434 {
01435 return m_table->text(row, col);
01436 }
01437
01438 void KexiCSVImportDialog::ignoreDuplicatesChanged(int)
01439 {
01440 fillTable();
01441 }
01442
01443 void KexiCSVImportDialog::slot1stRowForFieldNamesChanged(int)
01444 {
01445 m_adjustRows=1;
01446 if (m_1stRowForFieldNames->isChecked() && m_startline>0 && m_startline>=(m_startAtLineSpinBox->maxValue()-1))
01447 m_startline--;
01448 fillTable();
01449 }
01450
01451 void KexiCSVImportDialog::optionsButtonClicked()
01452 {
01453 KexiCSVImportOptionsDialog dlg(m_encoding, this);
01454 if (QDialog::Accepted != dlg.exec())
01455 return;
01456
01457 if (m_encoding != dlg.encodingComboBox()->selectedEncoding()) {
01458 m_encoding = dlg.encodingComboBox()->selectedEncoding();
01459 if (!openData())
01460 return;
01461 fillTable();
01462 }
01463 }
01464
01465 bool KexiCSVImportDialog::eventFilter ( QObject * watched, QEvent * e )
01466 {
01467 QEvent::Type t = e->type();
01468
01469 if (m_blockUserEvents && (t==QEvent::KeyPress || t==QEvent::KeyRelease
01470 || t==QEvent::MouseButtonPress || t==QEvent::MouseButtonDblClick
01471 || t==QEvent::Paint ))
01472 return true;
01473
01474 if (watched == m_startAtLineSpinBox && t==QEvent::KeyPress) {
01475 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
01476 if (ke->key()==Key_Enter || ke->key()==Key_Return) {
01477 m_table->setFocus();
01478 return true;
01479 }
01480 }
01481 return QDialog::eventFilter( watched, e );
01482 }
01483
01484 void KexiCSVImportDialog::slotPrimaryKeyFieldToggled(bool on)
01485 {
01486 Q_UNUSED(on);
01487 formatChanged(_PK_FLAG);
01488 }
01489
01490 void KexiCSVImportDialog::updateRowCountInfo()
01491 {
01493 m_infoLbl->setFileName( m_fname );
01494 }
01495
01496 #include "kexicsvimportdialog.moc"