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
#include <qbuttongroup.h>
00028
#include <qfile.h>
00029
#include <qlabel.h>
00030
#include <qlayout.h>
00031
#include <qlineedit.h>
00032
#include <qlistview.h>
00033
#include <qradiobutton.h>
00034
#include <qregexp.h>
00035
#include <qtable.h>
00036
#include <qtextstream.h>
00037
#include <qvbox.h>
00038
00039
#include <kapplication.h>
00040
#include <kdebug.h>
00041
#include <kcombobox.h>
00042
#include <kinputdialog.h>
00043
#include <klineedit.h>
00044
#include <klocale.h>
00045
#include <kprogress.h>
00046
#include <ksimpleconfig.h>
00047
#include <kstandarddirs.h>
00048
#include <kurlrequester.h>
00049
#include <kfiledialog.h>
00050
00051
#include "kimportdialog.h"
00052
#include "kimportdialog.moc"
00053
00054 KImportColumn::KImportColumn(KImportDialog *dlg,
const QString &header,
int count)
00055 : m_maxCount(count),
00056 m_refCount(0),
00057 m_header(header),
00058 mDialog(dlg)
00059 {
00060 mFormats.append(FormatPlain);
00061 mFormats.append(FormatUnquoted);
00062
00063
00064 mDefaultFormat = FormatUnquoted;
00065
00066 mDialog->addColumn(
this);
00067 }
00068
00069
QValueList<int> KImportColumn::formats()
00070 {
00071
return mFormats;
00072 }
00073
00074
QString KImportColumn::formatName(
int format)
00075 {
00076
switch (format) {
00077
case FormatPlain:
00078
return i18n(
"Plain");
00079
case FormatUnquoted:
00080
return i18n(
"Unquoted");
00081
case FormatBracketed:
00082
return i18n(
"Bracketed");
00083
default:
00084
return i18n(
"Undefined");
00085 }
00086 }
00087
00088
int KImportColumn::defaultFormat()
00089 {
00090
return mDefaultFormat;
00091 }
00092
00093
QString KImportColumn::preview(
const QString &value,
int format)
00094 {
00095
if (format == FormatBracketed) {
00096
return "(" + value +
")";
00097 }
else if (format == FormatUnquoted) {
00098
if (value.left(1) ==
"\"" && value.right(1) ==
"\"") {
00099
return value.mid(1,value.length()-2);
00100 }
else {
00101
return value;
00102 }
00103 }
else {
00104
return value;
00105 }
00106 }
00107
00108
void KImportColumn::addColId(
int id)
00109 {
00110 mColIds.append(
id);
00111 }
00112
00113
void KImportColumn::removeColId(
int id)
00114 {
00115 mColIds.remove(
id);
00116 }
00117
00118
QValueList<int> KImportColumn::colIdList()
00119 {
00120
return mColIds;
00121 }
00122
00123
QString KImportColumn::convert()
00124 {
00125
QValueList<int>::ConstIterator it = mColIds.begin();
00126
if (it == mColIds.end())
return "";
00127
else return mDialog->cell(*it);
00128 }
00129
00130
00131
class ColumnItem :
public QListViewItem {
00132
public:
00133 ColumnItem(KImportColumn *col,
QListView *parent) :
QListViewItem(parent), mColumn(col)
00134 {
00135 setText(0,mColumn->header());
00136 }
00137
00138 KImportColumn *column() {
return mColumn; }
00139
00140
private:
00141 KImportColumn *mColumn;
00142 };
00143
00151 KImportDialog::KImportDialog(
QWidget* parent)
00152 : KDialogBase(parent,"importdialog",true,i18n("Import Text File"),Ok|Cancel),
00153 mSeparator(","),
00154 mCurrentRow(0)
00155 {
00156 mData.setAutoDelete(
true );
00157
00158
QVBox *topBox =
new QVBox(
this);
00159 setMainWidget(topBox);
00160 topBox->setSpacing(spacingHint());
00161
00162
QHBox *fileBox =
new QHBox(topBox);
00163 fileBox->setSpacing(spacingHint());
00164
new QLabel(i18n(
"File to import:"),fileBox);
00165 KURLRequester *urlRequester =
new KURLRequester(fileBox);
00166 urlRequester->setFilter(
"*.csv" );
00167 connect(urlRequester,SIGNAL(returnPressed(
const QString &)),
00168 SLOT(setFile(
const QString &)));
00169 connect(urlRequester,SIGNAL(urlSelected(
const QString &)),
00170 SLOT(setFile(
const QString &)));
00171 connect(urlRequester->lineEdit(),SIGNAL(textChanged (
const QString & )),
00172 SLOT(slotUrlChanged(
const QString & )));
00173 mTable =
new QTable(5,5,topBox);
00174 mTable->setMinimumHeight( 150 );
00175 connect(mTable,SIGNAL(selectionChanged()),SLOT(tableSelected()));
00176
00177 QHBox *separatorBox =
new QHBox( topBox );
00178 separatorBox->setSpacing( spacingHint() );
00179
00180
new QLabel( i18n(
"Separator:" ), separatorBox );
00181
00182 mSeparatorCombo =
new KComboBox( separatorBox );
00183 mSeparatorCombo->insertItem(
"," );
00184 mSeparatorCombo->insertItem( i18n(
"Tab" ) );
00185 mSeparatorCombo->insertItem( i18n(
"Space" ) );
00186 mSeparatorCombo->insertItem(
"=" );
00187 mSeparatorCombo->insertItem(
";" );
00188 connect(mSeparatorCombo, SIGNAL( activated(
int) ),
00189
this, SLOT( separatorClicked(
int) ) );
00190 mSeparatorCombo->setCurrentItem( 0 );
00191
00192 QHBox *rowsBox =
new QHBox( topBox );
00193 rowsBox->setSpacing( spacingHint() );
00194
00195
new QLabel( i18n(
"Import starts at row:" ), rowsBox );
00196 mStartRow =
new QSpinBox( rowsBox );
00197 mStartRow->setMinValue( 1 );
00198
00199
00200
00201
00202
00203 QVBox *assignBox =
new QVBox(topBox);
00204 assignBox->setSpacing(spacingHint());
00205
00206 QHBox *listsBox =
new QHBox(assignBox);
00207 listsBox->setSpacing(spacingHint());
00208
00209 mHeaderList =
new QListView(listsBox);
00210 mHeaderList->addColumn(i18n(
"Header"));
00211 connect(mHeaderList, SIGNAL(selectionChanged(
QListViewItem*)),
00212
this, SLOT(headerSelected(
QListViewItem*)));
00213 connect(mHeaderList,SIGNAL(doubleClicked(
QListViewItem*)),
00214 SLOT(assignColumn(
QListViewItem *)));
00215
00216 mFormatCombo =
new KComboBox( listsBox );
00217 mFormatCombo->setDuplicatesEnabled(
false );
00218
00219
QPushButton *assignButton =
new QPushButton(i18n(
"Assign to Selected Column"),
00220 assignBox);
00221 connect(assignButton,SIGNAL(clicked()),SLOT(assignColumn()));
00222
00223 QPushButton *removeButton =
new QPushButton(i18n(
"Remove Assignment From Selected Column"),
00224 assignBox);
00225 connect(removeButton,SIGNAL(clicked()),SLOT(removeColumn()));
00226
00227 QPushButton *assignTemplateButton =
new QPushButton(i18n(
"Assign with Template..."),
00228 assignBox);
00229 connect(assignTemplateButton,SIGNAL(clicked()),SLOT(assignTemplate()));
00230
00231 QPushButton *saveTemplateButton =
new QPushButton(i18n(
"Save Current Template"),
00232 assignBox);
00233 connect(saveTemplateButton,SIGNAL(clicked()),SLOT(saveTemplate()));
00234
00235 resize(500,300);
00236
00237 connect(
this,SIGNAL(okClicked()),SLOT(applyConverter()));
00238 connect(
this,SIGNAL(applyClicked()),SLOT(applyConverter()));
00239 enableButtonOK(!urlRequester->lineEdit()->text().isEmpty());
00240 }
00241
00242
void KImportDialog::slotUrlChanged(
const QString & text)
00243 {
00244 enableButtonOK(!text.isEmpty());
00245 }
00246
00247
bool KImportDialog::setFile(
const QString& file)
00248 {
00249 enableButtonOK(!file.isEmpty());
00250 kdDebug(5300) <<
"KImportDialog::setFile(): " << file << endl;
00251
00252
QFile f(file);
00253
00254
if (f.open(IO_ReadOnly)) {
00255 mFile =
"";
00256
QTextStream t(&f);
00257 mFile = t.read();
00258
00259 f.close();
00260
00261 readFile();
00262
00263
00264
00265
return true;
00266 }
else {
00267 kdDebug(5300) <<
" Open failed" << endl;
00268
return false;
00269 }
00270 }
00271
00272
void KImportDialog::registerColumns()
00273 {
00274
QPtrListIterator<KImportColumn> colIt(mColumns);
00275
for (; colIt.current(); ++colIt) {
00276
new ColumnItem(*colIt,mHeaderList);
00277 }
00278 mHeaderList->setSelected(mHeaderList->firstChild(),
true);
00279 }
00280
00281
void KImportDialog::fillTable()
00282 {
00283
00284
00285
int row, column;
00286
00287
for (row = 0; row < mTable->numRows(); ++row)
00288
for (column = 0; column < mTable->numCols(); ++column)
00289 mTable->clearCell(row, column);
00290
00291
for ( row = 0; row < int(mData.count()); ++row ) {
00292
QValueVector<QString> *rowVector = mData[ row ];
00293
for( column = 0; column < int(rowVector->size()); ++column ) {
00294 setCellText( row, column, rowVector->at( column ) );
00295 }
00296 }
00297 }
00298
00299
void KImportDialog::readFile(
int rows )
00300 {
00301 kdDebug(5300) <<
"KImportDialog::readFile(): " << rows << endl;
00302
00303 mData.clear();
00304
00305
int row, column;
00306
enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
00307 S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
00308
00309
QChar m_textquote =
'"';
00310
int m_startline = 0;
00311
00312
QChar x;
00313
QString field =
"";
00314
00315 row = column = 0;
00316
QTextStream inputStream(mFile, IO_ReadOnly);
00317 inputStream.setEncoding(QTextStream::Locale);
00318
00319 KProgressDialog pDialog(
this, 0, i18n(
"Loading Progress"),
00320 i18n(
"Please wait while the file is loaded."),
true);
00321 pDialog.setAllowCancel(
true);
00322 pDialog.showCancelButton(
true);
00323 pDialog.setAutoClose(
true);
00324
00325 KProgress *progress = pDialog.progressBar();
00326 progress->setTotalSteps( mFile.contains(mSeparator,
false) );
00327 progress->setValue(0);
00328
int progressValue = 0;
00329
00330
if (progress->totalSteps() > 0)
00331 pDialog.show();
00332
00333
while (!inputStream.atEnd() && !pDialog.wasCancelled()) {
00334 inputStream >> x;
00335
00336
00337
if (x == mSeparator)
00338 {
00339 progress->setValue(progressValue++);
00340
if (progressValue % 15 == 0)
00341 kapp->processEvents();
00342 }
00343
00344
if (x ==
'\r') inputStream >> x;
00345
00346
switch (state) {
00347
case S_START :
00348
if (x == m_textquote) {
00349 field += x;
00350 state = S_QUOTED_FIELD;
00351 }
else if (x == mSeparator) {
00352 ++column;
00353 }
else if (x ==
'\n') {
00354 ++row;
00355 column = 0;
00356 }
else {
00357 field += x;
00358 state = S_MAYBE_NORMAL_FIELD;
00359 }
00360
break;
00361
case S_QUOTED_FIELD :
00362
if (x == m_textquote) {
00363 field += x;
00364 state = S_MAYBE_END_OF_QUOTED_FIELD;
00365 }
else if (x ==
'\n') {
00366 setData(row - m_startline, column, field);
00367 field =
"";
00368
if (x ==
'\n') {
00369 ++row;
00370 column = 0;
00371 }
else {
00372 ++column;
00373 }
00374 state = S_START;
00375 }
else {
00376 field += x;
00377 }
00378
break;
00379
case S_MAYBE_END_OF_QUOTED_FIELD :
00380
if (x == m_textquote) {
00381 field += x;
00382 state = S_QUOTED_FIELD;
00383 }
else if (x == mSeparator || x ==
'\n') {
00384 setData(row - m_startline, column, field);
00385 field =
"";
00386
if (x ==
'\n') {
00387 ++row;
00388 column = 0;
00389 }
else {
00390 ++column;
00391 }
00392 state = S_START;
00393 }
else {
00394 state = S_END_OF_QUOTED_FIELD;
00395 }
00396
break;
00397
case S_END_OF_QUOTED_FIELD :
00398
if (x == mSeparator || x ==
'\n') {
00399 setData(row - m_startline, column, field);
00400 field =
"";
00401
if (x ==
'\n') {
00402 ++row;
00403 column = 0;
00404 }
else {
00405 ++column;
00406 }
00407 state = S_START;
00408 }
else {
00409 state = S_END_OF_QUOTED_FIELD;
00410 }
00411
break;
00412
case S_MAYBE_NORMAL_FIELD :
00413
if (x == m_textquote) {
00414 field =
"";
00415 state = S_QUOTED_FIELD;
00416 }
00417
case S_NORMAL_FIELD :
00418
if (x == mSeparator || x ==
'\n') {
00419 setData(row - m_startline, column, field);
00420 field =
"";
00421
if (x ==
'\n') {
00422 ++row;
00423 column = 0;
00424 }
else {
00425 ++column;
00426 }
00427 state = S_START;
00428 }
else {
00429 field += x;
00430 }
00431 }
00432
00433
if ( rows > 0 && row > rows )
break;
00434 }
00435
00436 fillTable();
00437 }
00438
00439
void KImportDialog::setCellText(
int row,
int col,
const QString& text)
00440 {
00441
if (row < 0)
return;
00442
00443
if ((mTable->numRows() - 1) < row) mTable->setNumRows(row + 1);
00444
if ((mTable->numCols() - 1) < col) mTable->setNumCols(col + 1);
00445
00446 KImportColumn *c = mColumnDict.find(col);
00447
QString formattedText;
00448
if (c) formattedText = c->preview(text,findFormat(col));
00449
else formattedText = text;
00450 mTable->setText(row, col, formattedText);
00451 }
00452
00453
void KImportDialog::formatSelected(
QListViewItem*)
00454 {
00455
00456 }
00457
00458
void KImportDialog::headerSelected(
QListViewItem* item)
00459 {
00460 KImportColumn *col = ((ColumnItem *)item)->column();
00461
00462
if (!col)
return;
00463
00464 mFormatCombo->clear();
00465
00466
QValueList<int> formats = col->formats();
00467
00468
QValueList<int>::ConstIterator it = formats.begin();
00469
QValueList<int>::ConstIterator end = formats.end();
00470
while(it != end) {
00471 mFormatCombo->insertItem( col->formatName(*it), *it - 1 );
00472 ++it;
00473 }
00474
00475
QTableSelection selection = mTable->selection(mTable->currentSelection());
00476
00477 updateFormatSelection(selection.leftCol());
00478 }
00479
00480
void KImportDialog::updateFormatSelection(
int column)
00481 {
00482
int format = findFormat(column);
00483
00484
if ( format == KImportColumn::FormatUndefined )
00485 mFormatCombo->setCurrentItem( 0 );
00486
else
00487 mFormatCombo->setCurrentItem( format - 1 );
00488 }
00489
00490
void KImportDialog::tableSelected()
00491 {
00492
QTableSelection selection = mTable->selection(mTable->currentSelection());
00493
00494
QListViewItem *item = mHeaderList->firstChild();
00495 KImportColumn *col = mColumnDict.find(selection.leftCol());
00496
if (col) {
00497
while(item) {
00498
if (item->text(0) == col->header()) {
00499
break;
00500 }
00501 item = item->nextSibling();
00502 }
00503 }
00504
if (item) {
00505 mHeaderList->setSelected(item,
true);
00506 }
00507
00508 updateFormatSelection(selection.leftCol());
00509 }
00510
00511
void KImportDialog::separatorClicked(
int id)
00512 {
00513
switch(
id) {
00514
case 0:
00515 mSeparator =
',';
00516
break;
00517
case 1:
00518 mSeparator =
'\t';
00519
break;
00520
case 2:
00521 mSeparator =
' ';
00522
break;
00523
case 3:
00524 mSeparator =
'=';
00525
break;
00526
case 4:
00527 mSeparator =
';';
00528
break;
00529
default:
00530 mSeparator =
',';
00531
break;
00532 }
00533
00534 readFile();
00535 }
00536
00537
void KImportDialog::assignColumn(
QListViewItem *item)
00538 {
00539
if (!item)
return;
00540
00541
00542
00543
00544 ColumnItem *colItem = (ColumnItem *)item;
00545
00546
QTableSelection selection = mTable->selection(mTable->currentSelection());
00547
00548
00549
00550
for(
int i=selection.leftCol();i<=selection.rightCol();++i) {
00551
if (i >= 0) {
00552 mTable->horizontalHeader()->setLabel(i,colItem->text(0));
00553 mColumnDict.replace(i,colItem->column());
00554
int format = mFormatCombo->currentItem() + 1;
00555 mFormats.replace(i,format);
00556 colItem->column()->addColId(i);
00557 }
00558 }
00559
00560 readFile();
00561 }
00562
00563
void KImportDialog::assignColumn()
00564 {
00565 assignColumn(mHeaderList->currentItem());
00566 }
00567
00568
void KImportDialog::assignTemplate()
00569 {
00570
QMap<uint,int> columnMap;
00571
QMap<QString, QString> fileMap;
00572
QStringList templates;
00573
00574
00575
QStringList list = KGlobal::dirs()->findAllResources(
"data" ,
QString( kapp->name() ) +
00576
"/csv-templates/*.desktop",
true,
true );
00577
00578
for ( QStringList::iterator it = list.begin(); it != list.end(); ++it )
00579 {
00580 KSimpleConfig config( *it,
true );
00581
00582
if ( !config.hasGroup(
"csv column map" ) )
00583
continue;
00584
00585 config.setGroup(
"Misc" );
00586 templates.append( config.readEntry(
"Name" ) );
00587 fileMap.insert( config.readEntry(
"Name" ), *it );
00588 }
00589
00590
00591
bool ok =
false;
00592
QString tmp;
00593 tmp = KInputDialog::getItem( i18n(
"Template Selection" ),
00594 i18n(
"Please select a template, that matches the CSV file:" ),
00595 templates, 0,
false, &ok,
this );
00596
00597
if ( !ok )
00598
return;
00599
00600 KSimpleConfig config( fileMap[ tmp ],
true );
00601 config.setGroup(
"General" );
00602 uint numColumns = config.readUnsignedNumEntry(
"Columns" );
00603
int format = config.readNumEntry(
"Format" );
00604
00605
00606 config.setGroup(
"csv column map" );
00607
for ( uint i = 0; i < numColumns; ++i ) {
00608
int col = config.readNumEntry( QString::number( i ) );
00609 columnMap.insert( i, col );
00610 }
00611
00612
00613
for ( uint i = 0; i < columnMap.count(); ++i ) {
00614
int tableColumn = columnMap[i];
00615
if ( tableColumn == -1 )
00616
continue;
00617 KImportColumn *col = mColumns.at(i);
00618 mTable->horizontalHeader()->setLabel( tableColumn, col->header() );
00619 mColumnDict.replace( tableColumn, col );
00620 mFormats.replace( tableColumn, format );
00621 col->addColId( tableColumn );
00622 }
00623
00624 readFile();
00625 }
00626
00627
void KImportDialog::removeColumn()
00628 {
00629
QTableSelection selection = mTable->selection(mTable->currentSelection());
00630
00631
00632
00633
for(
int i=selection.leftCol();i<=selection.rightCol();++i) {
00634
if (i >= 0) {
00635 mTable->horizontalHeader()->setLabel(i,QString::number(i+1));
00636 KImportColumn *col = mColumnDict.find(i);
00637
if (col) {
00638 mColumnDict.remove(i);
00639 mFormats.remove(i);
00640 col->removeColId(i);
00641 }
00642 }
00643 }
00644
00645 readFile();
00646 }
00647
00648
void KImportDialog::applyConverter()
00649 {
00650 kdDebug(5300) <<
"KImportDialog::applyConverter" << endl;
00651
00652 KProgressDialog pDialog(
this, 0, i18n(
"Importing Progress"),
00653 i18n(
"Please wait while the data is imported."),
true);
00654 pDialog.setAllowCancel(
true);
00655 pDialog.showCancelButton(
true);
00656 pDialog.setAutoClose(
true);
00657
00658 KProgress *progress = pDialog.progressBar();
00659 progress->setTotalSteps( mTable->numRows()-1 );
00660 progress->setValue(0);
00661
00662 readFile( 0 );
00663
00664 pDialog.show();
00665
for( uint i = mStartRow->value() - 1; i < mData.count() && !pDialog.wasCancelled(); ++i ) {
00666 mCurrentRow = i;
00667 progress->setValue(i);
00668
if (i % 5 == 0)
00669 kapp->processEvents();
00670
00671 convertRow();
00672 }
00673 }
00674
00675
int KImportDialog::findFormat(
int column)
00676 {
00677
QMap<int,int>::ConstIterator formatIt = mFormats.find(column);
00678
int format;
00679
if (formatIt == mFormats.end()) format = KImportColumn::FormatUndefined;
00680
else format = *formatIt;
00681
00682
00683
00684
return format;
00685 }
00686
00687
QString KImportDialog::cell(uint col)
00688 {
00689
if ( col >= mData[ mCurrentRow ]->size() )
return "";
00690
else return data( mCurrentRow, col );
00691 }
00692
00693
void KImportDialog::addColumn(KImportColumn *col)
00694 {
00695 mColumns.append(col);
00696 }
00697
00698
void KImportDialog::setData( uint row, uint col,
const QString &value )
00699 {
00700
QString val = value;
00701 val.replace(
"\\n",
"\n" );
00702
00703
if ( row >= mData.count() ) {
00704 mData.resize( row + 1 );
00705 }
00706
00707
QValueVector<QString> *rowVector = mData[ row ];
00708
if ( !rowVector ) {
00709 rowVector =
new QValueVector<QString>;
00710 mData.insert( row, rowVector );
00711 }
00712
if ( col >= rowVector->size() ) {
00713 rowVector->resize( col + 1 );
00714 }
00715
00716 KImportColumn *c = mColumnDict.find( col );
00717
if ( c )
00718 rowVector->at( col ) = c->preview( val, findFormat(col) );
00719
else
00720 rowVector->at( col ) = val;
00721 }
00722
00723
QString KImportDialog::data( uint row, uint col )
00724 {
00725
return mData[ row ]->at( col );
00726 }
00727
00728
void KImportDialog::saveTemplate()
00729 {
00730
QString fileName = KFileDialog::getSaveFileName(
00731 locateLocal(
"data",
QString( kapp->name() ) +
"/csv-templates/" ),
00732
"*.desktop",
this );
00733
00734
if ( fileName.isEmpty() )
00735
return;
00736
00737
if ( !fileName.contains(
".desktop" ) )
00738 fileName +=
".desktop";
00739
00740
QString name = KInputDialog::getText( i18n(
"Template Name" ), i18n(
"Please enter a name for the template:" ) );
00741
00742
if ( name.isEmpty() )
00743
return;
00744
00745 KConfig config( fileName );
00746 config.setGroup(
"General" );
00747 config.writeEntry(
"Columns", mColumns.count() );
00748 config.writeEntry(
"Format", mFormatCombo->currentItem() + 1 );
00749
00750 config.setGroup(
"Misc" );
00751 config.writeEntry(
"Name", name );
00752
00753 config.setGroup(
"csv column map" );
00754
00755 KImportColumn *column;
00756 uint counter = 0;
00757
for ( column = mColumns.first(); column; column = mColumns.next() ) {
00758
QValueList<int> list = column->colIdList();
00759
if ( list.count() > 0 )
00760 config.writeEntry( QString::number( counter ), list[ 0 ] );
00761
else
00762 config.writeEntry( QString::number( counter ), -1 );
00763 counter++;
00764 }
00765
00766 config.sync();
00767 }