00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <qbuttongroup.h>
00024 #include <qcheckbox.h>
00025 #include <qcombobox.h>
00026 #include <qlabel.h>
00027 #include <qlayout.h>
00028 #include <qlineedit.h>
00029 #include <qpushbutton.h>
00030 #include <qradiobutton.h>
00031 #include <qtable.h>
00032 #include <qtextcodec.h>
00033 #include <qtooltip.h>
00034
00035 #include <kapplication.h>
00036 #include <kdebug.h>
00037 #include <kdialogbase.h>
00038 #include <kfiledialog.h>
00039 #include <klineedit.h>
00040 #include <klocale.h>
00041 #include <kinputdialog.h>
00042 #include <kmessagebox.h>
00043 #include <kprogress.h>
00044 #include <kstandarddirs.h>
00045 #include <kurlrequester.h>
00046
00047 #include "dateparser.h"
00048
00049 #include "csvimportdialog.h"
00050
00051 enum { Local = 0, Guess = 1, Latin1 = 2, Uni = 3, MSBug = 4, Codec = 5 };
00052
00053 CSVImportDialog::CSVImportDialog( KABC::AddressBook *ab, QWidget *parent,
00054 const char * name )
00055 : KDialogBase( Plain, i18n ( "CSV Import Dialog" ), Ok | Cancel | User1 |
00056 User2, Ok, parent, name, true, true ),
00057 mAdjustRows( false ),
00058 mStartLine( 0 ),
00059 mTextQuote( '"' ),
00060 mDelimiter( "," ),
00061 mAddressBook( ab )
00062 {
00063 initGUI();
00064
00065 mTypeMap.insert( i18n( "Undefined" ), Undefined );
00066 mTypeMap.insert( KABC::Addressee::formattedNameLabel(), FormattedName );
00067 mTypeMap.insert( KABC::Addressee::familyNameLabel(), FamilyName );
00068 mTypeMap.insert( KABC::Addressee::givenNameLabel(), GivenName );
00069 mTypeMap.insert( KABC::Addressee::additionalNameLabel(), AdditionalName );
00070 mTypeMap.insert( KABC::Addressee::prefixLabel(), Prefix );
00071 mTypeMap.insert( KABC::Addressee::suffixLabel(), Suffix );
00072 mTypeMap.insert( KABC::Addressee::nickNameLabel(), NickName );
00073 mTypeMap.insert( KABC::Addressee::birthdayLabel(), Birthday );
00074
00075 mTypeMap.insert( KABC::Addressee::homeAddressStreetLabel(), HomeAddressStreet );
00076 mTypeMap.insert( KABC::Addressee::homeAddressLocalityLabel(),
00077 HomeAddressLocality );
00078 mTypeMap.insert( KABC::Addressee::homeAddressRegionLabel(), HomeAddressRegion );
00079 mTypeMap.insert( KABC::Addressee::homeAddressPostalCodeLabel(),
00080 HomeAddressPostalCode );
00081 mTypeMap.insert( KABC::Addressee::homeAddressCountryLabel(),
00082 HomeAddressCountry );
00083 mTypeMap.insert( KABC::Addressee::homeAddressLabelLabel(), HomeAddressLabel );
00084
00085 mTypeMap.insert( KABC::Addressee::businessAddressStreetLabel(),
00086 BusinessAddressStreet );
00087 mTypeMap.insert( KABC::Addressee::businessAddressLocalityLabel(),
00088 BusinessAddressLocality );
00089 mTypeMap.insert( KABC::Addressee::businessAddressRegionLabel(),
00090 BusinessAddressRegion );
00091 mTypeMap.insert( KABC::Addressee::businessAddressPostalCodeLabel(),
00092 BusinessAddressPostalCode );
00093 mTypeMap.insert( KABC::Addressee::businessAddressCountryLabel(),
00094 BusinessAddressCountry );
00095 mTypeMap.insert( KABC::Addressee::businessAddressLabelLabel(),
00096 BusinessAddressLabel );
00097
00098 mTypeMap.insert( KABC::Addressee::homePhoneLabel(), HomePhone );
00099 mTypeMap.insert( KABC::Addressee::businessPhoneLabel(), BusinessPhone );
00100 mTypeMap.insert( KABC::Addressee::mobilePhoneLabel(), MobilePhone );
00101 mTypeMap.insert( KABC::Addressee::homeFaxLabel(), HomeFax );
00102 mTypeMap.insert( KABC::Addressee::businessFaxLabel(), BusinessFax );
00103 mTypeMap.insert( KABC::Addressee::carPhoneLabel(), CarPhone );
00104 mTypeMap.insert( KABC::Addressee::isdnLabel(), Isdn );
00105 mTypeMap.insert( KABC::Addressee::pagerLabel(), Pager );
00106 mTypeMap.insert( KABC::Addressee::emailLabel(), Email );
00107 mTypeMap.insert( KABC::Addressee::mailerLabel(), Mailer );
00108 mTypeMap.insert( KABC::Addressee::titleLabel(), Title );
00109 mTypeMap.insert( KABC::Addressee::roleLabel(), Role );
00110 mTypeMap.insert( KABC::Addressee::organizationLabel(), Organization );
00111 mTypeMap.insert( KABC::Addressee::noteLabel(), Note );
00112 mTypeMap.insert( KABC::Addressee::urlLabel(), URL );
00113
00114 mCustomCounter = mTypeMap.count();
00115 int count = mCustomCounter;
00116
00117 KABC::Field::List fields = mAddressBook->fields( KABC::Field::CustomCategory );
00118 KABC::Field::List::Iterator it;
00119 for ( it = fields.begin(); it != fields.end(); ++it, ++count )
00120 mTypeMap.insert( (*it)->label(), count );
00121
00122 reloadCodecs();
00123
00124 connect( mDelimiterBox, SIGNAL( clicked( int ) ),
00125 this, SLOT( delimiterClicked( int ) ) );
00126 connect( mDelimiterEdit, SIGNAL( returnPressed() ),
00127 this, SLOT( returnPressed() ) );
00128 connect( mDelimiterEdit, SIGNAL( textChanged ( const QString& ) ),
00129 this, SLOT( textChanged ( const QString& ) ) );
00130 connect( mComboLine, SIGNAL( activated( const QString& ) ),
00131 this, SLOT( lineSelected( const QString& ) ) );
00132 connect( mComboQuote, SIGNAL( activated( const QString& ) ),
00133 this, SLOT( textquoteSelected( const QString& ) ) );
00134 connect( mIgnoreDuplicates, SIGNAL( stateChanged( int ) ),
00135 this, SLOT( ignoreDuplicatesChanged( int ) ) );
00136 connect( mCodecCombo, SIGNAL( activated( const QString& ) ),
00137 this, SLOT( codecChanged() ) );
00138
00139 connect( mUrlRequester, SIGNAL( returnPressed( const QString& ) ),
00140 this, SLOT( setFile( const QString& ) ) );
00141 connect( mUrlRequester, SIGNAL( urlSelected( const QString& ) ),
00142 this, SLOT( setFile( const QString& ) ) );
00143 connect( mUrlRequester->lineEdit(), SIGNAL( textChanged ( const QString& ) ),
00144 this, SLOT( urlChanged( const QString& ) ) );
00145
00146 connect( this, SIGNAL( user1Clicked() ),
00147 this, SLOT( applyTemplate() ) );
00148
00149 connect( this, SIGNAL( user2Clicked() ),
00150 this, SLOT( saveTemplate() ) );
00151 }
00152
00153 CSVImportDialog::~CSVImportDialog()
00154 {
00155 mCodecs.clear();
00156 }
00157
00158 KABC::AddresseeList CSVImportDialog::contacts() const
00159 {
00160 DateParser dateParser( mDatePatternEdit->text() );
00161 KABC::AddresseeList contacts;
00162
00163 KProgressDialog progressDialog( mPage );
00164 progressDialog.setAutoClose( true );
00165 progressDialog.progressBar()->setTotalSteps( mTable->numRows() );
00166 progressDialog.setLabel( i18n( "Importing contacts" ) );
00167 progressDialog.show();
00168
00169 kapp->processEvents();
00170
00171 for ( int row = 1; row < mTable->numRows(); ++row ) {
00172 KABC::Addressee a;
00173 bool emptyRow = true;
00174 KABC::Address addrHome( KABC::Address::Home );
00175 KABC::Address addrWork( KABC::Address::Work );
00176 for ( int col = 0; col < mTable->numCols(); ++col ) {
00177 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00178 col ) );
00179 if ( !item ) {
00180 kdError() << "ERROR: item cast failed" << endl;
00181 continue;
00182 }
00183
00184 QString value = mTable->text( row, col );
00185 if ( !value.isEmpty() )
00186 emptyRow = false;
00187
00188 switch ( posToType( item->currentItem() ) ) {
00189 case Undefined:
00190 continue;
00191 break;
00192 case FormattedName:
00193 a.setFormattedName( value );
00194 break;
00195 case GivenName:
00196 a.setGivenName( value );
00197 break;
00198 case FamilyName:
00199 a.setFamilyName( value );
00200 break;
00201 case AdditionalName:
00202 a.setAdditionalName( value );
00203 break;
00204 case Prefix:
00205 a.setPrefix( value );
00206 break;
00207 case Suffix:
00208 a.setSuffix( value );
00209 break;
00210 case NickName:
00211 a.setNickName( value );
00212 break;
00213 case Birthday:
00214 a.setBirthday( dateParser.parse( value ) );
00215 break;
00216 case Email:
00217 if ( !value.isEmpty() )
00218 a.insertEmail( value, true );
00219 break;
00220 case Role:
00221 a.setRole( value );
00222 break;
00223 case Title:
00224 a.setTitle( value );
00225 break;
00226 case Mailer:
00227 a.setMailer( value );
00228 break;
00229 case URL:
00230 a.setUrl( KURL( value ) );
00231 break;
00232 case Organization:
00233 a.setOrganization( value );
00234 break;
00235 case Note:
00236 a.setNote( value );
00237 break;
00238
00239 case HomePhone:
00240 if ( !value.isEmpty() ) {
00241 KABC::PhoneNumber number( value, KABC::PhoneNumber::Home );
00242 a.insertPhoneNumber( number );
00243 }
00244 break;
00245 case BusinessPhone:
00246 if ( !value.isEmpty() ) {
00247 KABC::PhoneNumber number( value, KABC::PhoneNumber::Work );
00248 a.insertPhoneNumber( number );
00249 }
00250 break;
00251 case MobilePhone:
00252 if ( !value.isEmpty() ) {
00253 KABC::PhoneNumber number( value, KABC::PhoneNumber::Cell );
00254 a.insertPhoneNumber( number );
00255 }
00256 break;
00257 case HomeFax:
00258 if ( !value.isEmpty() ) {
00259 KABC::PhoneNumber number( value, KABC::PhoneNumber::Home |
00260 KABC::PhoneNumber::Fax );
00261 a.insertPhoneNumber( number );
00262 }
00263 break;
00264 case BusinessFax:
00265 if ( !value.isEmpty() ) {
00266 KABC::PhoneNumber number( value, KABC::PhoneNumber::Work |
00267 KABC::PhoneNumber::Fax );
00268 a.insertPhoneNumber( number );
00269 }
00270 break;
00271 case CarPhone:
00272 if ( !value.isEmpty() ) {
00273 KABC::PhoneNumber number( value, KABC::PhoneNumber::Car );
00274 a.insertPhoneNumber( number );
00275 }
00276 break;
00277 case Isdn:
00278 if ( !value.isEmpty() ) {
00279 KABC::PhoneNumber number( value, KABC::PhoneNumber::Isdn );
00280 a.insertPhoneNumber( number );
00281 }
00282 break;
00283 case Pager:
00284 if ( !value.isEmpty() ) {
00285 KABC::PhoneNumber number( value, KABC::PhoneNumber::Pager );
00286 a.insertPhoneNumber( number );
00287 }
00288 break;
00289
00290 case HomeAddressStreet:
00291 addrHome.setStreet( value );
00292 break;
00293 case HomeAddressLocality:
00294 addrHome.setLocality( value );
00295 break;
00296 case HomeAddressRegion:
00297 addrHome.setRegion( value );
00298 break;
00299 case HomeAddressPostalCode:
00300 addrHome.setPostalCode( value );
00301 break;
00302 case HomeAddressCountry:
00303 addrHome.setCountry( value );
00304 break;
00305 case HomeAddressLabel:
00306 addrHome.setLabel( value );
00307 break;
00308
00309 case BusinessAddressStreet:
00310 addrWork.setStreet( value );
00311 break;
00312 case BusinessAddressLocality:
00313 addrWork.setLocality( value );
00314 break;
00315 case BusinessAddressRegion:
00316 addrWork.setRegion( value );
00317 break;
00318 case BusinessAddressPostalCode:
00319 addrWork.setPostalCode( value );
00320 break;
00321 case BusinessAddressCountry:
00322 addrWork.setCountry( value );
00323 break;
00324 case BusinessAddressLabel:
00325 addrWork.setLabel( value );
00326 break;
00327 default:
00328 KABC::Field::List fields = mAddressBook->fields( KABC::Field::CustomCategory );
00329 KABC::Field::List::Iterator it;
00330
00331 int counter = 0;
00332 for ( it = fields.begin(); it != fields.end(); ++it ) {
00333 if ( counter == (int)( posToType( item->currentItem() ) - mCustomCounter ) ) {
00334 (*it)->setValue( a, value );
00335 continue;
00336 }
00337 ++counter;
00338 }
00339 break;
00340 }
00341 }
00342
00343 kapp->processEvents();
00344
00345 if ( progressDialog.wasCancelled() )
00346 return KABC::AddresseeList();
00347
00348 progressDialog.progressBar()->advance( 1 );
00349
00350 if ( !addrHome.isEmpty() )
00351 a.insertAddress( addrHome );
00352 if ( !addrWork.isEmpty() )
00353 a.insertAddress( addrWork );
00354
00355 if ( !emptyRow && !a.isEmpty() )
00356 contacts.append( a );
00357 }
00358
00359 return contacts;
00360 }
00361
00362 void CSVImportDialog::initGUI()
00363 {
00364 mPage = plainPage();
00365
00366 QGridLayout *layout = new QGridLayout( mPage, 1, 1, marginHint(),
00367 spacingHint() );
00368 QHBoxLayout *hbox = new QHBoxLayout();
00369 hbox->setSpacing( spacingHint() );
00370
00371 QLabel *label = new QLabel( i18n( "File to import:" ), mPage );
00372 hbox->addWidget( label );
00373
00374 mUrlRequester = new KURLRequester( mPage );
00375 mUrlRequester->setFilter( "*.csv" );
00376 hbox->addWidget( mUrlRequester );
00377
00378 layout->addMultiCellLayout( hbox, 0, 0, 0, 4 );
00379
00380 // Delimiter: comma, semicolon, tab, space, other
00381 mDelimiterBox = new QButtonGroup( i18n( "Delimiter" ), mPage );
00382 mDelimiterBox->setColumnLayout( 0, Qt::Vertical );
00383 mDelimiterBox->layout()->setSpacing( spacingHint() );
00384 mDelimiterBox->layout()->setMargin( marginHint() );
00385 QGridLayout *delimiterLayout = new QGridLayout( mDelimiterBox->layout() );
00386 delimiterLayout->setAlignment( Qt::AlignTop );
00387 layout->addMultiCellWidget( mDelimiterBox, 1, 4, 0, 0 );
00388
00389 mRadioComma = new QRadioButton( i18n( "Comma" ), mDelimiterBox );
00390 mRadioComma->setChecked( true );
00391 delimiterLayout->addWidget( mRadioComma, 0, 0 );
00392
00393 mRadioSemicolon = new QRadioButton( i18n( "Semicolon" ), mDelimiterBox );
00394 delimiterLayout->addWidget( mRadioSemicolon, 0, 1 );
00395
00396 mRadioTab = new QRadioButton( i18n( "Tabulator" ), mDelimiterBox );
00397 delimiterLayout->addWidget( mRadioTab, 1, 0 );
00398
00399 mRadioSpace = new QRadioButton( i18n( "Space" ), mDelimiterBox );
00400 delimiterLayout->addWidget( mRadioSpace, 1, 1 );
00401
00402 mRadioOther = new QRadioButton( i18n( "Other" ), mDelimiterBox );
00403 delimiterLayout->addWidget( mRadioOther, 0, 2 );
00404
00405 mDelimiterEdit = new QLineEdit( mDelimiterBox );
00406 delimiterLayout->addWidget( mDelimiterEdit, 1, 2 );
00407
00408 mComboLine = new QComboBox( false, mPage );
00409 mComboLine->insertItem( i18n( "1" ) );
00410 layout->addWidget( mComboLine, 2, 3 );
00411
00412 mComboQuote = new QComboBox( false, mPage );
00413 mComboQuote->insertItem( i18n( "\"" ), 0 );
00414 mComboQuote->insertItem( i18n( "'" ), 1 );
00415 mComboQuote->insertItem( i18n( "None" ), 2 );
00416 layout->addWidget( mComboQuote, 2, 2 );
00417
00418 mDatePatternEdit = new QLineEdit( mPage );
00419 mDatePatternEdit->setText( "Y-M-D" );
00420 QToolTip::add( mDatePatternEdit, i18n( "<ul><li>y: year with 2 digits</li>"
00421 "<li>Y: year with 4 digits</li>"
00422 "<li>m: month with 1 or 2 digits</li>"
00423 "<li>M: month with 2 digits</li>"
00424 "<li>d: day with 1 or 2 digits</li>"
00425 "<li>D: day with 2 digits</li></ul>" ) );
00426 layout->addWidget( mDatePatternEdit, 2, 4 );
00427
00428 label = new QLabel( i18n( "Start at line:" ), mPage );
00429 layout->addWidget( label, 1, 3 );
00430
00431 label = new QLabel( i18n( "Textquote:" ), mPage );
00432 layout->addWidget( label, 1, 2 );
00433
00434 label = new QLabel( i18n( "Date format:" ), mPage );
00435 layout->addWidget( label, 1, 4 );
00436
00437 mIgnoreDuplicates = new QCheckBox( mPage );
00438 mIgnoreDuplicates->setText( i18n( "Ignore duplicate delimiters" ) );
00439 layout->addMultiCellWidget( mIgnoreDuplicates, 3, 3, 2, 4 );
00440
00441 mCodecCombo = new QComboBox( mPage );
00442 layout->addMultiCellWidget( mCodecCombo, 4, 4, 2, 4 );
00443
00444 mTable = new QTable( 0, 0, mPage );
00445 mTable->setSelectionMode( QTable::NoSelection );
00446 mTable->horizontalHeader()->hide();
00447 layout->addMultiCellWidget( mTable, 5, 5, 0, 4 );
00448
00449 setButtonText( User1, i18n( "Apply Template..." ) );
00450 setButtonText( User2, i18n( "Save Template..." ) );
00451
00452 enableButtonOK( false );
00453 actionButton( User1 )->setEnabled( false );
00454 actionButton( User2 )->setEnabled( false );
00455
00456 resize( 400, 300 );
00457 }
00458
00459 void CSVImportDialog::fillTable()
00460 {
00461 int row, column;
00462 bool lastCharDelimiter = false;
00463 bool ignoreDups = mIgnoreDuplicates->isChecked();
00464 enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
00465 S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
00466
00467 QChar x;
00468 QString field;
00469
00470
00471 mTypeStore.clear();
00472 for ( column = 0; column < mTable->numCols(); ++column ) {
00473 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00474 column ) );
00475 if ( !item || mClearTypeStore )
00476 mTypeStore.append( typeToPos( Undefined ) );
00477 else if ( item )
00478 mTypeStore.append( item->currentItem() );
00479 }
00480
00481 clearTable();
00482
00483 row = column = 1;
00484 mData = QString( mFileArray );
00485
00486 QTextStream inputStream( mData, IO_ReadOnly );
00487
00488
00489 int code = mCodecCombo->currentItem();
00490 if ( code >= Codec )
00491 inputStream.setCodec( mCodecs.at( code - Codec ) );
00492 else if ( code == Uni )
00493 inputStream.setEncoding( QTextStream::Unicode );
00494 else if ( code == MSBug )
00495 inputStream.setEncoding( QTextStream::UnicodeReverse );
00496 else if ( code == Latin1 )
00497 inputStream.setEncoding( QTextStream::Latin1 );
00498 else if ( code == Guess ) {
00499 QTextCodec* codec = QTextCodec::codecForContent( mFileArray.data(), mFileArray.size() );
00500 if ( codec ) {
00501 KMessageBox::information( this, i18n( "Using codec '%1'" ).arg( codec->name() ), i18n( "Encoding" ) );
00502 inputStream.setCodec( codec );
00503 }
00504 }
00505
00506 int maxColumn = 0;
00507 while ( !inputStream.atEnd() ) {
00508 inputStream >> x;
00509
00510 if ( x == '\r' ) inputStream >> x;
00511
00512 switch ( state ) {
00513 case S_START :
00514 if ( x == mTextQuote ) {
00515 state = S_QUOTED_FIELD;
00516 } else if ( x == mDelimiter ) {
00517 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00518 ++column;
00519 lastCharDelimiter = true;
00520 } else if ( x == '\n' ) {
00521 ++row;
00522 column = 1;
00523 } else {
00524 field += x;
00525 state = S_MAYBE_NORMAL_FIELD;
00526 }
00527 break;
00528 case S_QUOTED_FIELD :
00529 if ( x == mTextQuote ) {
00530 state = S_MAYBE_END_OF_QUOTED_FIELD;
00531 } else if ( x == '\n' ) {
00532 setText( row - mStartLine + 1, column, field );
00533 field = "";
00534 if ( x == '\n' ) {
00535 ++row;
00536 column = 1;
00537 } else {
00538 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00539 ++column;
00540 lastCharDelimiter = true;
00541 }
00542 state = S_START;
00543 } else {
00544 field += x;
00545 }
00546 break;
00547 case S_MAYBE_END_OF_QUOTED_FIELD :
00548 if ( x == mTextQuote ) {
00549 field += x;
00550 state = S_QUOTED_FIELD;
00551 } else if ( x == mDelimiter || x == '\n' ) {
00552 setText( row - mStartLine + 1, column, field );
00553 field = "";
00554 if ( x == '\n' ) {
00555 ++row;
00556 column = 1;
00557 } else {
00558 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00559 ++column;
00560 lastCharDelimiter = true;
00561 }
00562 state = S_START;
00563 } else {
00564 state = S_END_OF_QUOTED_FIELD;
00565 }
00566 break;
00567 case S_END_OF_QUOTED_FIELD :
00568 if ( x == mDelimiter || x == '\n' ) {
00569 setText( row - mStartLine + 1, column, field );
00570 field = "";
00571 if ( x == '\n' ) {
00572 ++row;
00573 column = 1;
00574 } else {
00575 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00576 ++column;
00577 lastCharDelimiter = true;
00578 }
00579 state = S_START;
00580 } else {
00581 state = S_END_OF_QUOTED_FIELD;
00582 }
00583 break;
00584 case S_MAYBE_NORMAL_FIELD :
00585 if ( x == mTextQuote ) {
00586 field = "";
00587 state = S_QUOTED_FIELD;
00588 break;
00589 }
00590 case S_NORMAL_FIELD :
00591 if ( x == mDelimiter || x == '\n' ) {
00592 setText( row - mStartLine + 1, column, field );
00593 field = "";
00594 if ( x == '\n' ) {
00595 ++row;
00596 column = 1;
00597 } else {
00598 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00599 ++column;
00600 lastCharDelimiter = true;
00601 }
00602 state = S_START;
00603 } else {
00604 field += x;
00605 }
00606 }
00607 if ( x != mDelimiter )
00608 lastCharDelimiter = false;
00609
00610 if ( column > maxColumn )
00611 maxColumn = column;
00612 }
00613
00614
00615 if ( field.length() > 0 ) {
00616 setText( row - mStartLine + 1, column, field );
00617 ++row;
00618 field = "";
00619 }
00620
00621 adjustRows( row - mStartLine );
00622 mTable->setNumCols( maxColumn );
00623
00624 for ( column = 0; column < mTable->numCols(); ++column ) {
00625 QComboTableItem *item = new QComboTableItem( mTable, mTypeMap.keys() );
00626 mTable->setItem( 0, column, item );
00627 if ( column < (int)mTypeStore.count() )
00628 item->setCurrentItem( mTypeStore[ column ] );
00629 else
00630 item->setCurrentItem( typeToPos( Undefined ) );
00631 mTable->adjustColumn( column );
00632 }
00633 }
00634
00635 void CSVImportDialog::clearTable()
00636 {
00637 for ( int row = 0; row < mTable->numRows(); ++row )
00638 for ( int column = 0; column < mTable->numCols(); ++column )
00639 mTable->clearCell( row, column );
00640 }
00641
00642 void CSVImportDialog::fillComboBox()
00643 {
00644 mComboLine->clear();
00645 for ( int row = 1; row < mTable->numRows() + 1; ++row )
00646 mComboLine->insertItem( QString::number( row ), row - 1 );
00647 }
00648
00649 void CSVImportDialog::reloadCodecs()
00650 {
00651 mCodecCombo->clear();
00652
00653 mCodecs.clear();
00654
00655 QTextCodec *codec;
00656 for ( int i = 0; ( codec = QTextCodec::codecForIndex( i ) ); i++ )
00657 mCodecs.append( codec );
00658
00659 mCodecCombo->insertItem( i18n( "Local (%1)" ).arg( QTextCodec::codecForLocale()->name() ), Local );
00660 mCodecCombo->insertItem( i18n( "[guess]" ), Guess );
00661 mCodecCombo->insertItem( i18n( "Latin1" ), Latin1 );
00662 mCodecCombo->insertItem( i18n( "Unicode" ), Uni );
00663 mCodecCombo->insertItem( i18n( "Microsoft Unicode" ), MSBug );
00664
00665 for ( uint i = 0; i < mCodecs.count(); i++ )
00666 mCodecCombo->insertItem( mCodecs.at( i )->name(), Codec + i );
00667 }
00668
00669 void CSVImportDialog::setText( int row, int col, const QString& text )
00670 {
00671 if ( row < 1 )
00672 return;
00673
00674 if ( mTable->numRows() < row ) {
00675 mTable->setNumRows( row + 5000 );
00676 mAdjustRows = true;
00677 }
00678
00679 if ( mTable->numCols() < col )
00680 mTable->setNumCols( col + 50 );
00681
00682 mTable->setText( row - 1, col - 1, text );
00683 }
00684
00685
00686
00687
00688 void CSVImportDialog::adjustRows( int rows )
00689 {
00690 if ( mAdjustRows ) {
00691 mTable->setNumRows( rows );
00692 mAdjustRows = false;
00693 }
00694 }
00695
00696 void CSVImportDialog::returnPressed()
00697 {
00698 if ( mDelimiterBox->id( mDelimiterBox->selected() ) != 4 )
00699 return;
00700
00701 mDelimiter = mDelimiterEdit->text();
00702 fillTable();
00703 }
00704
00705 void CSVImportDialog::textChanged ( const QString& )
00706 {
00707 mRadioOther->setChecked ( true );
00708 delimiterClicked( 4 );
00709 }
00710
00711 void CSVImportDialog::delimiterClicked( int id )
00712 {
00713 switch ( id ) {
00714 case 0:
00715 mDelimiter = ",";
00716 break;
00717 case 4:
00718 mDelimiter = mDelimiterEdit->text();
00719 break;
00720 case 2:
00721 mDelimiter = "\t";
00722 break;
00723 case 3:
00724 mDelimiter = " ";
00725 break;
00726 case 1:
00727 mDelimiter = ";";
00728 break;
00729 }
00730
00731 fillTable();
00732 }
00733
00734 void CSVImportDialog::textquoteSelected( const QString& mark )
00735 {
00736 if ( mComboQuote->currentItem() == 2 )
00737 mTextQuote = 0;
00738 else
00739 mTextQuote = mark[ 0 ];
00740
00741 fillTable();
00742 }
00743
00744 void CSVImportDialog::lineSelected( const QString& line )
00745 {
00746 mStartLine = line.toInt() - 1;
00747 fillTable();
00748 }
00749
00750 void CSVImportDialog::slotOk()
00751 {
00752 bool assigned = false;
00753
00754 for ( int column = 0; column < mTable->numCols(); ++column ) {
00755 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00756 column ) );
00757 if ( item && posToType( item->currentItem() ) != Undefined )
00758 assigned = true;
00759 }
00760
00761 if ( assigned )
00762 KDialogBase::slotOk();
00763 else
00764 KMessageBox::sorry( this, i18n( "You have to assign at least one column." ) );
00765 }
00766
00767 void CSVImportDialog::applyTemplate()
00768 {
00769 QMap<uint,int> columnMap;
00770 QMap<QString, QString> fileMap;
00771 QStringList templates;
00772
00773
00774 QStringList list = KGlobal::dirs()->findAllResources( "data" , QString( kapp->name() ) +
00775 "/csv-templates/*.desktop", true, true );
00776
00777 for ( QStringList::iterator it = list.begin(); it != list.end(); ++it )
00778 {
00779 KSimpleConfig config( *it, true );
00780
00781 if ( !config.hasGroup( "csv column map" ) )
00782 continue;
00783
00784 config.setGroup( "Misc" );
00785 templates.append( config.readEntry( "Name" ) );
00786 fileMap.insert( config.readEntry( "Name" ), *it );
00787 }
00788
00789
00790 bool ok = false;
00791 QString tmp;
00792 tmp = KInputDialog::getItem( i18n( "Template Selection" ),
00793 i18n( "Please select a template, that matches the CSV file:" ),
00794 templates, 0, false, &ok, this );
00795
00796 if ( !ok )
00797 return;
00798
00799 KSimpleConfig config( fileMap[ tmp ], true );
00800 config.setGroup( "General" );
00801 mDatePatternEdit->setText( config.readEntry( "DatePattern", "Y-M-D" ) );
00802 uint numColumns = config.readUnsignedNumEntry( "Columns" );
00803 mDelimiterEdit->setText( config.readEntry( "DelimiterOther" ) );
00804 mDelimiterBox->setButton( config.readNumEntry( "DelimiterType" ) );
00805 delimiterClicked( config.readNumEntry( "DelimiterType" ) );
00806 int quoteType = config.readNumEntry( "QuoteType" );
00807 mComboQuote->setCurrentItem( quoteType );
00808 textquoteSelected( mComboQuote->currentText() );
00809
00810
00811 config.setGroup( "csv column map" );
00812 for ( uint i = 0; i < numColumns; ++i ) {
00813 int col = config.readNumEntry( QString::number( i ) );
00814 columnMap.insert( i, col );
00815 }
00816
00817
00818 for ( uint column = 0; column < columnMap.count(); ++column ) {
00819 int type = columnMap[ column ];
00820 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00821 column ) );
00822 if ( item )
00823 item->setCurrentItem( typeToPos( type ) );
00824 }
00825 }
00826
00827 void CSVImportDialog::saveTemplate()
00828 {
00829 QString fileName = KFileDialog::getSaveFileName(
00830 locateLocal( "data", QString( kapp->name() ) + "/csv-templates/" ),
00831 "*.desktop", this );
00832
00833 if ( fileName.isEmpty() )
00834 return;
00835
00836 if ( !fileName.contains( ".desktop" ) )
00837 fileName += ".desktop";
00838
00839 QString name = KInputDialog::getText( i18n( "Template Name" ), i18n( "Please enter a name for the template:" ) );
00840
00841 if ( name.isEmpty() )
00842 return;
00843
00844 KConfig config( fileName );
00845 config.setGroup( "General" );
00846 config.writeEntry( "DatePattern", mDatePatternEdit->text() );
00847 config.writeEntry( "Columns", mTable->numCols() );
00848 config.writeEntry( "DelimiterType", mDelimiterBox->id( mDelimiterBox->selected() ) );
00849 config.writeEntry( "DelimiterOther", mDelimiterEdit->text() );
00850 config.writeEntry( "QuoteType", mComboQuote->currentItem() );
00851
00852 config.setGroup( "Misc" );
00853 config.writeEntry( "Name", name );
00854
00855 config.setGroup( "csv column map" );
00856
00857 for ( int column = 0; column < mTable->numCols(); ++column ) {
00858 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00859 column ) );
00860 if ( item )
00861 config.writeEntry( QString::number( column ), posToType(
00862 item->currentItem() ) );
00863 else
00864 config.writeEntry( QString::number( column ), 0 );
00865 }
00866
00867 config.sync();
00868 }
00869
00870 QString CSVImportDialog::getText( int row, int col )
00871 {
00872 return mTable->text( row, col );
00873 }
00874
00875 uint CSVImportDialog::posToType( int pos ) const
00876 {
00877 uint counter = 0;
00878 QMap<QString, uint>::ConstIterator it;
00879 for ( it = mTypeMap.begin(); it != mTypeMap.end(); ++it, ++counter )
00880 if ( counter == (uint)pos )
00881 return it.data();
00882
00883 return 0;
00884 }
00885
00886 int CSVImportDialog::typeToPos( uint type ) const
00887 {
00888 uint counter = 0;
00889 QMap<QString, uint>::ConstIterator it;
00890 for ( it = mTypeMap.begin(); it != mTypeMap.end(); ++it, ++counter )
00891 if ( it.data() == type )
00892 return counter;
00893
00894 return -1;
00895 }
00896
00897 void CSVImportDialog::ignoreDuplicatesChanged( int )
00898 {
00899 fillTable();
00900 }
00901
00902 void CSVImportDialog::setFile( const QString &fileName )
00903 {
00904 if ( fileName.isEmpty() )
00905 return;
00906
00907 QFile file( fileName );
00908 if ( !file.open( IO_ReadOnly ) ) {
00909 KMessageBox::sorry( this, i18n( "Cannot open input file." ) );
00910 file.close();
00911 return;
00912 }
00913
00914 mFileArray = file.readAll();
00915 file.close();
00916
00917 mClearTypeStore = true;
00918 clearTable();
00919 mTable->setNumCols( 0 );
00920 mTable->setNumRows( 0 );
00921 fillTable();
00922 mClearTypeStore = false;
00923
00924 fillComboBox();
00925 }
00926
00927 void CSVImportDialog::urlChanged( const QString &file )
00928 {
00929 bool state = !file.isEmpty();
00930
00931 enableButtonOK( state );
00932 actionButton( User1 )->setEnabled( state );
00933 actionButton( User2 )->setEnabled( state );
00934 }
00935
00936 void CSVImportDialog::codecChanged()
00937 {
00938 fillTable();
00939 }
00940
00941 #include <csvimportdialog.moc>