kaddressbook Library API Documentation

csvimportdialog.cpp

00001 /* 00002 This file is part of KAddressBook. 00003 Copyright (C) 2003 Tobias Koenig <tokoe@kde.org> 00004 based on the code of KSpread's CSV Import Dialog 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. 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" ); // ISO 8601 format as default 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 // store previous assignment 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 // find the current codec 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; // read one char 00509 00510 if ( x == '\r' ) inputStream >> x; // eat '\r', to handle DOS/LOSEDOWS files correctly 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 // file with only one line without '\n' 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 ) // skipped by the user 00672 return; 00673 00674 if ( mTable->numRows() < row ) { 00675 mTable->setNumRows( row + 5000 ); // We add 5000 at a time to limit recalculations 00676 mAdjustRows = true; 00677 } 00678 00679 if ( mTable->numCols() < col ) 00680 mTable->setNumCols( col + 50 ); // We add 50 at a time to limit recalculation 00681 00682 mTable->setText( row - 1, col - 1, text ); 00683 } 00684 00685 /* 00686 * Called after the first fillTable() when number of rows are unknown. 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 ); // other 00709 } 00710 00711 void CSVImportDialog::delimiterClicked( int id ) 00712 { 00713 switch ( id ) { 00714 case 0: // comma 00715 mDelimiter = ","; 00716 break; 00717 case 4: // other 00718 mDelimiter = mDelimiterEdit->text(); 00719 break; 00720 case 2: // tab 00721 mDelimiter = "\t"; 00722 break; 00723 case 3: // space 00724 mDelimiter = " "; 00725 break; 00726 case 1: // semicolon 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 // load all template files 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 // let the user chose, what to take 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 // create the column map 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 // apply the column map 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>
KDE Logo
This file is part of the documentation for kaddressbook Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 1 15:19:04 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003