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 ( 1 == row && static_cast<QTableItem *>(item)->text() == value )
00186 // we are looking at a header row, stop now
00187 break;
00188
00189 if ( !value.isEmpty() )
00190 emptyRow = false;
00191
00192 switch ( posToType( item->currentItem() ) ) {
00193 case Undefined:
00194 continue;
00195 break;
00196 case FormattedName:
00197 a.setFormattedName( value );
00198 break;
00199 case GivenName:
00200 a.setGivenName( value );
00201 break;
00202 case FamilyName:
00203 a.setFamilyName( value );
00204 break;
00205 case AdditionalName:
00206 a.setAdditionalName( value );
00207 break;
00208 case Prefix:
00209 a.setPrefix( value );
00210 break;
00211 case Suffix:
00212 a.setSuffix( value );
00213 break;
00214 case NickName:
00215 a.setNickName( value );
00216 break;
00217 case Birthday:
00218 a.setBirthday( dateParser.parse( value ) );
00219 break;
00220 case Email:
00221 if ( !value.isEmpty() )
00222 a.insertEmail( value, true );
00223 break;
00224 case Role:
00225 a.setRole( value );
00226 break;
00227 case Title:
00228 a.setTitle( value );
00229 break;
00230 case Mailer:
00231 a.setMailer( value );
00232 break;
00233 case URL:
00234 a.setUrl( KURL( value ) );
00235 break;
00236 case Organization:
00237 a.setOrganization( value );
00238 break;
00239 case Note:
00240 a.setNote( a.note() + value + "\n" );
00241 break;
00242
00243 case HomePhone:
00244 if ( !value.isEmpty() ) {
00245 KABC::PhoneNumber number( value, KABC::PhoneNumber::Home );
00246 a.insertPhoneNumber( number );
00247 }
00248 break;
00249 case BusinessPhone:
00250 if ( !value.isEmpty() ) {
00251 KABC::PhoneNumber number( value, KABC::PhoneNumber::Work );
00252 a.insertPhoneNumber( number );
00253 }
00254 break;
00255 case MobilePhone:
00256 if ( !value.isEmpty() ) {
00257 KABC::PhoneNumber number( value, KABC::PhoneNumber::Cell );
00258 a.insertPhoneNumber( number );
00259 }
00260 break;
00261 case HomeFax:
00262 if ( !value.isEmpty() ) {
00263 KABC::PhoneNumber number( value, KABC::PhoneNumber::Home |
00264 KABC::PhoneNumber::Fax );
00265 a.insertPhoneNumber( number );
00266 }
00267 break;
00268 case BusinessFax:
00269 if ( !value.isEmpty() ) {
00270 KABC::PhoneNumber number( value, KABC::PhoneNumber::Work |
00271 KABC::PhoneNumber::Fax );
00272 a.insertPhoneNumber( number );
00273 }
00274 break;
00275 case CarPhone:
00276 if ( !value.isEmpty() ) {
00277 KABC::PhoneNumber number( value, KABC::PhoneNumber::Car );
00278 a.insertPhoneNumber( number );
00279 }
00280 break;
00281 case Isdn:
00282 if ( !value.isEmpty() ) {
00283 KABC::PhoneNumber number( value, KABC::PhoneNumber::Isdn );
00284 a.insertPhoneNumber( number );
00285 }
00286 break;
00287 case Pager:
00288 if ( !value.isEmpty() ) {
00289 KABC::PhoneNumber number( value, KABC::PhoneNumber::Pager );
00290 a.insertPhoneNumber( number );
00291 }
00292 break;
00293
00294 case HomeAddressStreet:
00295 addrHome.setStreet( value );
00296 break;
00297 case HomeAddressLocality:
00298 addrHome.setLocality( value );
00299 break;
00300 case HomeAddressRegion:
00301 addrHome.setRegion( value );
00302 break;
00303 case HomeAddressPostalCode:
00304 addrHome.setPostalCode( value );
00305 break;
00306 case HomeAddressCountry:
00307 addrHome.setCountry( value );
00308 break;
00309 case HomeAddressLabel:
00310 addrHome.setLabel( value );
00311 break;
00312
00313 case BusinessAddressStreet:
00314 addrWork.setStreet( value );
00315 break;
00316 case BusinessAddressLocality:
00317 addrWork.setLocality( value );
00318 break;
00319 case BusinessAddressRegion:
00320 addrWork.setRegion( value );
00321 break;
00322 case BusinessAddressPostalCode:
00323 addrWork.setPostalCode( value );
00324 break;
00325 case BusinessAddressCountry:
00326 addrWork.setCountry( value );
00327 break;
00328 case BusinessAddressLabel:
00329 addrWork.setLabel( value );
00330 break;
00331 default:
00332 KABC::Field::List fields = mAddressBook->fields( KABC::Field::CustomCategory );
00333 KABC::Field::List::Iterator it;
00334
00335 int counter = 0;
00336 for ( it = fields.begin(); it != fields.end(); ++it ) {
00337 if ( counter == (int)( posToType( item->currentItem() ) - mCustomCounter ) ) {
00338 (*it)->setValue( a, value );
00339 break;
00340 }
00341 ++counter;
00342 }
00343 break;
00344 }
00345 }
00346
00347 kapp->processEvents();
00348
00349 if ( progressDialog.wasCancelled() )
00350 return KABC::AddresseeList();
00351
00352 progressDialog.progressBar()->advance( 1 );
00353
00354 if ( !addrHome.isEmpty() )
00355 a.insertAddress( addrHome );
00356 if ( !addrWork.isEmpty() )
00357 a.insertAddress( addrWork );
00358
00359 if ( !emptyRow && !a.isEmpty() )
00360 contacts.append( a );
00361 }
00362
00363 return contacts;
00364 }
00365
00366 void CSVImportDialog::initGUI()
00367 {
00368 mPage = plainPage();
00369
00370 QGridLayout *layout = new QGridLayout( mPage, 1, 1, marginHint(),
00371 spacingHint() );
00372 QHBoxLayout *hbox = new QHBoxLayout();
00373 hbox->setSpacing( spacingHint() );
00374
00375 QLabel *label = new QLabel( i18n( "File to import:" ), mPage );
00376 hbox->addWidget( label );
00377
00378 mUrlRequester = new KURLRequester( mPage );
00379 mUrlRequester->setFilter( "*.csv" );
00380 hbox->addWidget( mUrlRequester );
00381
00382 layout->addMultiCellLayout( hbox, 0, 0, 0, 4 );
00383
00384 // Delimiter: comma, semicolon, tab, space, other
00385 mDelimiterBox = new QButtonGroup( i18n( "Delimiter" ), mPage );
00386 mDelimiterBox->setColumnLayout( 0, Qt::Vertical );
00387 mDelimiterBox->layout()->setSpacing( spacingHint() );
00388 mDelimiterBox->layout()->setMargin( marginHint() );
00389 QGridLayout *delimiterLayout = new QGridLayout( mDelimiterBox->layout() );
00390 delimiterLayout->setAlignment( Qt::AlignTop );
00391 layout->addMultiCellWidget( mDelimiterBox, 1, 4, 0, 0 );
00392
00393 mRadioComma = new QRadioButton( i18n( "Comma" ), mDelimiterBox );
00394 mRadioComma->setChecked( true );
00395 delimiterLayout->addWidget( mRadioComma, 0, 0 );
00396
00397 mRadioSemicolon = new QRadioButton( i18n( "Semicolon" ), mDelimiterBox );
00398 delimiterLayout->addWidget( mRadioSemicolon, 0, 1 );
00399
00400 mRadioTab = new QRadioButton( i18n( "Tabulator" ), mDelimiterBox );
00401 delimiterLayout->addWidget( mRadioTab, 1, 0 );
00402
00403 mRadioSpace = new QRadioButton( i18n( "Space" ), mDelimiterBox );
00404 delimiterLayout->addWidget( mRadioSpace, 1, 1 );
00405
00406 mRadioOther = new QRadioButton( i18n( "Other" ), mDelimiterBox );
00407 delimiterLayout->addWidget( mRadioOther, 0, 2 );
00408
00409 mDelimiterEdit = new QLineEdit( mDelimiterBox );
00410 delimiterLayout->addWidget( mDelimiterEdit, 1, 2 );
00411
00412 mComboLine = new QComboBox( false, mPage );
00413 mComboLine->insertItem( i18n( "1" ) );
00414 layout->addWidget( mComboLine, 2, 3 );
00415
00416 mComboQuote = new QComboBox( false, mPage );
00417 mComboQuote->insertItem( i18n( "\"" ), 0 );
00418 mComboQuote->insertItem( i18n( "'" ), 1 );
00419 mComboQuote->insertItem( i18n( "None" ), 2 );
00420 layout->addWidget( mComboQuote, 2, 2 );
00421
00422 mDatePatternEdit = new QLineEdit( mPage );
00423 mDatePatternEdit->setText( "Y-M-D" );
00424 QToolTip::add( mDatePatternEdit, i18n( "<ul><li>y: year with 2 digits</li>"
00425 "<li>Y: year with 4 digits</li>"
00426 "<li>m: month with 1 or 2 digits</li>"
00427 "<li>M: month with 2 digits</li>"
00428 "<li>d: day with 1 or 2 digits</li>"
00429 "<li>D: day with 2 digits</li></ul>" ) );
00430 layout->addWidget( mDatePatternEdit, 2, 4 );
00431
00432 label = new QLabel( i18n( "Start at line:" ), mPage );
00433 layout->addWidget( label, 1, 3 );
00434
00435 label = new QLabel( i18n( "Textquote:" ), mPage );
00436 layout->addWidget( label, 1, 2 );
00437
00438 label = new QLabel( i18n( "Date format:" ), mPage );
00439 layout->addWidget( label, 1, 4 );
00440
00441 mIgnoreDuplicates = new QCheckBox( mPage );
00442 mIgnoreDuplicates->setText( i18n( "Ignore duplicate delimiters" ) );
00443 layout->addMultiCellWidget( mIgnoreDuplicates, 3, 3, 2, 4 );
00444
00445 mCodecCombo = new QComboBox( mPage );
00446 layout->addMultiCellWidget( mCodecCombo, 4, 4, 2, 4 );
00447
00448 mTable = new QTable( 0, 0, mPage );
00449 mTable->setSelectionMode( QTable::NoSelection );
00450 mTable->horizontalHeader()->hide();
00451 layout->addMultiCellWidget( mTable, 5, 5, 0, 4 );
00452
00453 setButtonText( User1, i18n( "Apply Template..." ) );
00454 setButtonText( User2, i18n( "Save Template..." ) );
00455
00456 enableButtonOK( false );
00457 actionButton( User1 )->setEnabled( false );
00458 actionButton( User2 )->setEnabled( false );
00459
00460 resize( 400, 300 );
00461 }
00462
00463 void CSVImportDialog::fillTable()
00464 {
00465 int row, column;
00466 bool lastCharDelimiter = false;
00467 bool ignoreDups = mIgnoreDuplicates->isChecked();
00468 enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
00469 S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
00470
00471 QChar x;
00472 QString field;
00473
00474
00475 mTypeStore.clear();
00476 for ( column = 0; column < mTable->numCols(); ++column ) {
00477 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00478 column ) );
00479 if ( !item || mClearTypeStore )
00480 mTypeStore.append( typeToPos( Undefined ) );
00481 else if ( item )
00482 mTypeStore.append( item->currentItem() );
00483 }
00484
00485 clearTable();
00486
00487 row = column = 1;
00488
00489 QTextStream inputStream( mFileArray, IO_ReadOnly );
00490
00491
00492 int code = mCodecCombo->currentItem();
00493 if ( code == Local )
00494 inputStream.setEncoding( QTextStream::Locale );
00495 else if ( code >= Codec )
00496 inputStream.setCodec( mCodecs.at( code - Codec ) );
00497 else if ( code == Uni )
00498 inputStream.setEncoding( QTextStream::Unicode );
00499 else if ( code == MSBug )
00500 inputStream.setEncoding( QTextStream::UnicodeReverse );
00501 else if ( code == Latin1 )
00502 inputStream.setEncoding( QTextStream::Latin1 );
00503 else if ( code == Guess ) {
00504 QTextCodec* codec = QTextCodec::codecForContent( mFileArray.data(), mFileArray.size() );
00505 if ( codec ) {
00506 KMessageBox::information( this, i18n( "Using codec '%1'" ).arg( codec->name() ), i18n( "Encoding" ) );
00507 inputStream.setCodec( codec );
00508 }
00509 }
00510
00511 int maxColumn = 0;
00512 while ( !inputStream.atEnd() ) {
00513 inputStream >> x;
00514
00515 if ( x == '\r' ) inputStream >> x;
00516
00517 switch ( state ) {
00518 case S_START :
00519 if ( x == mTextQuote ) {
00520 state = S_QUOTED_FIELD;
00521 } else if ( x == mDelimiter ) {
00522 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00523 ++column;
00524 lastCharDelimiter = true;
00525 } else if ( x == '\n' ) {
00526 ++row;
00527 column = 1;
00528 } else {
00529 field += x;
00530 state = S_MAYBE_NORMAL_FIELD;
00531 }
00532 break;
00533 case S_QUOTED_FIELD :
00534 if ( x == mTextQuote ) {
00535 state = S_MAYBE_END_OF_QUOTED_FIELD;
00536 } else if ( x == '\n' && mTextQuote.isNull() ) {
00537 setText( row - mStartLine + 1, column, field );
00538 field = "";
00539 if ( x == '\n' ) {
00540 ++row;
00541 column = 1;
00542 } else {
00543 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00544 ++column;
00545 lastCharDelimiter = true;
00546 }
00547 state = S_START;
00548 } else {
00549 field += x;
00550 }
00551 break;
00552 case S_MAYBE_END_OF_QUOTED_FIELD :
00553 if ( x == mTextQuote ) {
00554 field += x;
00555 state = S_QUOTED_FIELD;
00556 } else if ( x == mDelimiter || x == '\n' ) {
00557 setText( row - mStartLine + 1, column, field );
00558 field = "";
00559 if ( x == '\n' ) {
00560 ++row;
00561 column = 1;
00562 } else {
00563 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00564 ++column;
00565 lastCharDelimiter = true;
00566 }
00567 state = S_START;
00568 } else {
00569 state = S_END_OF_QUOTED_FIELD;
00570 }
00571 break;
00572 case S_END_OF_QUOTED_FIELD :
00573 if ( x == mDelimiter || x == '\n' ) {
00574 setText( row - mStartLine + 1, column, field );
00575 field = "";
00576 if ( x == '\n' ) {
00577 ++row;
00578 column = 1;
00579 } else {
00580 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00581 ++column;
00582 lastCharDelimiter = true;
00583 }
00584 state = S_START;
00585 } else {
00586 state = S_END_OF_QUOTED_FIELD;
00587 }
00588 break;
00589 case S_MAYBE_NORMAL_FIELD :
00590 if ( x == mTextQuote ) {
00591 field = "";
00592 state = S_QUOTED_FIELD;
00593 break;
00594 }
00595 case S_NORMAL_FIELD :
00596 if ( x == mDelimiter || x == '\n' ) {
00597 setText( row - mStartLine + 1, column, field );
00598 field = "";
00599 if ( x == '\n' ) {
00600 ++row;
00601 column = 1;
00602 } else {
00603 if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
00604 ++column;
00605 lastCharDelimiter = true;
00606 }
00607 state = S_START;
00608 } else {
00609 field += x;
00610 }
00611 }
00612 if ( x != mDelimiter )
00613 lastCharDelimiter = false;
00614
00615 if ( column > maxColumn )
00616 maxColumn = column;
00617 }
00618
00619
00620 if ( field.length() > 0 ) {
00621 setText( row - mStartLine + 1, column, field );
00622 ++row;
00623 field = "";
00624 }
00625
00626 adjustRows( row - mStartLine );
00627 mTable->setNumCols( maxColumn );
00628
00629 for ( column = 0; column < mTable->numCols(); ++column ) {
00630 QComboTableItem *item = new QComboTableItem( mTable, mTypeMap.keys() );
00631 mTable->setItem( 0, column, item );
00632 if ( column < (int)mTypeStore.count() )
00633 item->setCurrentItem( mTypeStore[ column ] );
00634 else
00635 item->setCurrentItem( typeToPos( Undefined ) );
00636 mTable->adjustColumn( column );
00637 }
00638
00639 resizeColumns();
00640 }
00641
00642 void CSVImportDialog::clearTable()
00643 {
00644 for ( int row = 0; row < mTable->numRows(); ++row )
00645 for ( int column = 0; column < mTable->numCols(); ++column )
00646 mTable->clearCell( row, column );
00647 }
00648
00649 void CSVImportDialog::fillComboBox()
00650 {
00651 mComboLine->clear();
00652 for ( int row = 1; row < mTable->numRows() + 1; ++row )
00653 mComboLine->insertItem( QString::number( row ), row - 1 );
00654 }
00655
00656 void CSVImportDialog::reloadCodecs()
00657 {
00658 mCodecCombo->clear();
00659
00660 mCodecs.clear();
00661
00662 QTextCodec *codec;
00663 for ( int i = 0; ( codec = QTextCodec::codecForIndex( i ) ); i++ )
00664 mCodecs.append( codec );
00665
00666 mCodecCombo->insertItem( i18n( "Local (%1)" ).arg( QTextCodec::codecForLocale()->name() ), Local );
00667 mCodecCombo->insertItem( i18n( "[guess]" ), Guess );
00668 mCodecCombo->insertItem( i18n( "Latin1" ), Latin1 );
00669 mCodecCombo->insertItem( i18n( "Unicode" ), Uni );
00670 mCodecCombo->insertItem( i18n( "Microsoft Unicode" ), MSBug );
00671
00672 for ( uint i = 0; i < mCodecs.count(); i++ )
00673 mCodecCombo->insertItem( mCodecs.at( i )->name(), Codec + i );
00674 }
00675
00676 void CSVImportDialog::setText( int row, int col, const QString& text )
00677 {
00678 if ( row < 1 )
00679 return;
00680
00681 if ( mTable->numRows() < row ) {
00682 mTable->setNumRows( row + 5000 );
00683 mAdjustRows = true;
00684 }
00685
00686 if ( mTable->numCols() < col )
00687 mTable->setNumCols( col + 50 );
00688
00689 mTable->setText( row - 1, col - 1, text );
00690 }
00691
00692
00693
00694
00695 void CSVImportDialog::adjustRows( int rows )
00696 {
00697 if ( mAdjustRows ) {
00698 mTable->setNumRows( rows );
00699 mAdjustRows = false;
00700 }
00701 }
00702
00703 void CSVImportDialog::resizeColumns()
00704 {
00705 QFontMetrics fm = fontMetrics();
00706 int width = 0;
00707
00708 QMap<QString, uint>::ConstIterator it;
00709 for ( it = mTypeMap.begin(); it != mTypeMap.end(); ++it ) {
00710 width = QMAX( width, fm.width( it.key() ) );
00711 }
00712
00713 for ( int i = 0; i < mTable->numCols(); ++i )
00714 mTable->setColumnWidth( i, QMAX( width + 15, mTable->columnWidth( i ) ) );
00715 }
00716
00717 void CSVImportDialog::returnPressed()
00718 {
00719 if ( mDelimiterBox->id( mDelimiterBox->selected() ) != 4 )
00720 return;
00721
00722 mDelimiter = mDelimiterEdit->text();
00723 fillTable();
00724 }
00725
00726 void CSVImportDialog::textChanged ( const QString& )
00727 {
00728 mRadioOther->setChecked ( true );
00729 delimiterClicked( 4 );
00730 }
00731
00732 void CSVImportDialog::delimiterClicked( int id )
00733 {
00734 switch ( id ) {
00735 case 0:
00736 mDelimiter = ",";
00737 break;
00738 case 4:
00739 mDelimiter = mDelimiterEdit->text();
00740 break;
00741 case 2:
00742 mDelimiter = "\t";
00743 break;
00744 case 3:
00745 mDelimiter = " ";
00746 break;
00747 case 1:
00748 mDelimiter = ";";
00749 break;
00750 }
00751
00752 fillTable();
00753 }
00754
00755 void CSVImportDialog::textquoteSelected( const QString& mark )
00756 {
00757 if ( mComboQuote->currentItem() == 2 )
00758 mTextQuote = 0;
00759 else
00760 mTextQuote = mark[ 0 ];
00761
00762 fillTable();
00763 }
00764
00765 void CSVImportDialog::lineSelected( const QString& line )
00766 {
00767 mStartLine = line.toInt() - 1;
00768 fillTable();
00769 }
00770
00771 void CSVImportDialog::slotOk()
00772 {
00773 bool assigned = false;
00774
00775 for ( int column = 0; column < mTable->numCols(); ++column ) {
00776 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00777 column ) );
00778 if ( item && posToType( item->currentItem() ) != Undefined )
00779 assigned = true;
00780 }
00781
00782 if ( assigned )
00783 KDialogBase::slotOk();
00784 else
00785 KMessageBox::sorry( this, i18n( "You have to assign at least one column." ) );
00786 }
00787
00788 void CSVImportDialog::applyTemplate()
00789 {
00790 QMap<uint,int> columnMap;
00791 QMap<QString, QString> fileMap;
00792 QStringList templates;
00793
00794
00795 QStringList list = KGlobal::dirs()->findAllResources( "data" , QString( kapp->name() ) +
00796 "/csv-templates/*.desktop", true, true );
00797
00798 for ( QStringList::iterator it = list.begin(); it != list.end(); ++it )
00799 {
00800 KSimpleConfig config( *it, true );
00801
00802 if ( !config.hasGroup( "csv column map" ) )
00803 continue;
00804
00805 config.setGroup( "Misc" );
00806 templates.append( config.readEntry( "Name" ) );
00807 fileMap.insert( config.readEntry( "Name" ), *it );
00808 }
00809
00810
00811 bool ok = false;
00812 QString tmp;
00813 tmp = KInputDialog::getItem( i18n( "Template Selection" ),
00814 i18n( "Please select a template, that matches the CSV file:" ),
00815 templates, 0, false, &ok, this );
00816
00817 if ( !ok )
00818 return;
00819
00820 KSimpleConfig config( fileMap[ tmp ], true );
00821 config.setGroup( "General" );
00822 mDatePatternEdit->setText( config.readEntry( "DatePattern", "Y-M-D" ) );
00823 uint numColumns = config.readUnsignedNumEntry( "Columns" );
00824 mDelimiterEdit->setText( config.readEntry( "DelimiterOther" ) );
00825 mDelimiterBox->setButton( config.readNumEntry( "DelimiterType" ) );
00826 delimiterClicked( config.readNumEntry( "DelimiterType" ) );
00827 int quoteType = config.readNumEntry( "QuoteType" );
00828 mComboQuote->setCurrentItem( quoteType );
00829 textquoteSelected( mComboQuote->currentText() );
00830
00831
00832 config.setGroup( "csv column map" );
00833 for ( uint i = 0; i < numColumns; ++i ) {
00834 int col = config.readNumEntry( QString::number( i ) );
00835 columnMap.insert( i, col );
00836 }
00837
00838
00839 for ( uint column = 0; column < columnMap.count(); ++column ) {
00840 int type = columnMap[ column ];
00841 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00842 column ) );
00843 if ( item )
00844 item->setCurrentItem( typeToPos( type ) );
00845 }
00846 }
00847
00848 void CSVImportDialog::saveTemplate()
00849 {
00850 QString fileName = KFileDialog::getSaveFileName(
00851 locateLocal( "data", QString( kapp->name() ) + "/csv-templates/" ),
00852 "*.desktop", this );
00853
00854 if ( fileName.isEmpty() )
00855 return;
00856
00857 if ( !fileName.contains( ".desktop" ) )
00858 fileName += ".desktop";
00859
00860 QString name = KInputDialog::getText( i18n( "Template Name" ), i18n( "Please enter a name for the template:" ) );
00861
00862 if ( name.isEmpty() )
00863 return;
00864
00865 KConfig config( fileName );
00866 config.setGroup( "General" );
00867 config.writeEntry( "DatePattern", mDatePatternEdit->text() );
00868 config.writeEntry( "Columns", mTable->numCols() );
00869 config.writeEntry( "DelimiterType", mDelimiterBox->id( mDelimiterBox->selected() ) );
00870 config.writeEntry( "DelimiterOther", mDelimiterEdit->text() );
00871 config.writeEntry( "QuoteType", mComboQuote->currentItem() );
00872
00873 config.setGroup( "Misc" );
00874 config.writeEntry( "Name", name );
00875
00876 config.setGroup( "csv column map" );
00877
00878 for ( int column = 0; column < mTable->numCols(); ++column ) {
00879 QComboTableItem *item = static_cast<QComboTableItem*>( mTable->item( 0,
00880 column ) );
00881 if ( item )
00882 config.writeEntry( QString::number( column ), posToType(
00883 item->currentItem() ) );
00884 else
00885 config.writeEntry( QString::number( column ), 0 );
00886 }
00887
00888 config.sync();
00889 }
00890
00891 QString CSVImportDialog::getText( int row, int col )
00892 {
00893 return mTable->text( row, col );
00894 }
00895
00896 uint CSVImportDialog::posToType( int pos ) const
00897 {
00898 uint counter = 0;
00899 QMap<QString, uint>::ConstIterator it;
00900 for ( it = mTypeMap.begin(); it != mTypeMap.end(); ++it, ++counter )
00901 if ( counter == (uint)pos )
00902 return it.data();
00903
00904 return 0;
00905 }
00906
00907 int CSVImportDialog::typeToPos( uint type ) const
00908 {
00909 uint counter = 0;
00910 QMap<QString, uint>::ConstIterator it;
00911 for ( it = mTypeMap.begin(); it != mTypeMap.end(); ++it, ++counter )
00912 if ( it.data() == type )
00913 return counter;
00914
00915 return -1;
00916 }
00917
00918 void CSVImportDialog::ignoreDuplicatesChanged( int )
00919 {
00920 fillTable();
00921 }
00922
00923 void CSVImportDialog::setFile( const QString &fileName )
00924 {
00925 if ( fileName.isEmpty() )
00926 return;
00927
00928 QFile file( fileName );
00929 if ( !file.open( IO_ReadOnly ) ) {
00930 KMessageBox::sorry( this, i18n( "Cannot open input file." ) );
00931 file.close();
00932 return;
00933 }
00934
00935 mFileArray = file.readAll();
00936 file.close();
00937
00938 mClearTypeStore = true;
00939 clearTable();
00940 mTable->setNumCols( 0 );
00941 mTable->setNumRows( 0 );
00942 fillTable();
00943 mClearTypeStore = false;
00944
00945 fillComboBox();
00946 }
00947
00948 void CSVImportDialog::urlChanged( const QString &file )
00949 {
00950 bool state = !file.isEmpty();
00951
00952 enableButtonOK( state );
00953 actionButton( User1 )->setEnabled( state );
00954 actionButton( User2 )->setEnabled( state );
00955 }
00956
00957 void CSVImportDialog::codecChanged()
00958 {
00959 fillTable();
00960 }
00961
00962 #include <csvimportdialog.moc>