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