libkdepim Library API Documentation

addresseelineedit.cpp

00001 /*
00002     This file is part of libkdepim.
00003     Copyright (c) 2002 Helge Deller <deller@gmx.de>
00004                   2002 Lubos Lunak <llunak@suse.cz>
00005                   2001,2003 Carsten Pfeiffer <pfeiffer@kde.org>
00006                   2001 Waldo Bastian <bastian@kde.org>
00007                   2004 Daniel Molkentin <danimo@klaralvdalens-datakonsult.se>
00008                   2004 Karl-Heinz Zimmer <khz@klaralvdalens-datakonsult.se>
00009 
00010     This library is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU Library General Public
00012     License as published by the Free Software Foundation; either
00013     version 2 of the License, or (at your option) any later version.
00014 
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Library General Public License for more details.
00019 
00020     You should have received a copy of the GNU Library General Public License
00021     along with this library; see the file COPYING.LIB.  If not, write to
00022     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023     Boston, MA 02111-1307, USA.
00024 */
00025 
00026 #include "addresseelineedit.h"
00027 
00028 #include <kabc/distributionlist.h>
00029 #include <kabc/stdaddressbook.h>
00030 #include <kabc/resource.h>
00031 
00032 #include <kcompletionbox.h>
00033 #include <kcursor.h>
00034 #include <kdebug.h>
00035 #include <kstandarddirs.h>
00036 #include <kstaticdeleter.h>
00037 #include <kstdaccel.h>
00038 #include <kurldrag.h>
00039 #include <klocale.h>
00040 
00041 #include "completionordereditor.h"
00042 #include "ldapclient.h"
00043 
00044 #include <qpopupmenu.h>
00045 #include <qapplication.h>
00046 #include <qobject.h>
00047 #include <qptrlist.h>
00048 #include <qregexp.h>
00049 #include <qevent.h>
00050 #include <qdragobject.h>
00051 #include <qclipboard.h>
00052 #include "resourceabc.h"
00053 
00054 using namespace KPIM;
00055 
00056 KCompletion * AddresseeLineEdit::s_completion = 0L;
00057 bool AddresseeLineEdit::s_addressesDirty = false;
00058 QTimer* AddresseeLineEdit::s_LDAPTimer = 0L;
00059 KPIM::LdapSearch* AddresseeLineEdit::s_LDAPSearch = 0L;
00060 QString* AddresseeLineEdit::s_LDAPText = 0L;
00061 AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
00062 KConfig *AddresseeLineEdit::s_config = 0L;
00063 
00064 static KStaticDeleter<KCompletion> completionDeleter;
00065 static KStaticDeleter<QTimer> ldapTimerDeleter;
00066 static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
00067 static KStaticDeleter<QString> ldapTextDeleter;
00068 static KStaticDeleter<KConfig> configDeleter;
00069 
00070 // needs to be unique, but the actual name doesn't matter much
00071 static QCString newLineEditDCOPObjectName()
00072 {
00073     static int s_count = 0;
00074     QCString name( "KPIM::AddresseeLineEdit" );
00075     if ( s_count++ ) {
00076       name += '-';
00077       name += QCString().setNum( s_count );
00078     }
00079     return name;
00080 }
00081 
00082 AddresseeLineEdit::AddresseeLineEdit( QWidget* parent, bool useCompletion,
00083                                       const char *name )
00084   : ClickLineEdit( parent, QString::null, name ), DCOPObject( newLineEditDCOPObjectName() )
00085 {
00086   m_useCompletion = useCompletion;
00087   m_completionInitialized = false;
00088   m_smartPaste = false;
00089   m_addressBookConnected = false;
00090 
00091   init();
00092 
00093   if ( m_useCompletion )
00094     s_addressesDirty = true;
00095 }
00096 
00097 
00098 void AddresseeLineEdit::init()
00099 {
00100   if ( !s_completion ) {
00101     completionDeleter.setObject( s_completion, new KCompletion() );
00102     s_completion->setOrder( KCompletion::Weighted );
00103     s_completion->setIgnoreCase( true );
00104   }
00105 
00106 //  connect( s_completion, SIGNAL( match( const QString& ) ),
00107 //           this, SLOT( slotMatched( const QString& ) ) );
00108 
00109   if ( m_useCompletion ) {
00110     if ( !s_LDAPTimer ) {
00111       ldapTimerDeleter.setObject( s_LDAPTimer, new QTimer );
00112       ldapSearchDeleter.setObject( s_LDAPSearch, new KPIM::LdapSearch );
00113       ldapTextDeleter.setObject( s_LDAPText, new QString );
00114     }
00115     if ( !m_completionInitialized ) {
00116       setCompletionObject( s_completion, false );
00117       connect( this, SIGNAL( completion( const QString& ) ),
00118           this, SLOT( slotCompletion() ) );
00119 
00120       KCompletionBox *box = completionBox();
00121       connect( box, SIGNAL( highlighted( const QString& ) ),
00122           this, SLOT( slotPopupCompletion( const QString& ) ) );
00123       connect( box, SIGNAL( userCancelled( const QString& ) ),
00124           SLOT( slotUserCancelled( const QString& ) ) );
00125 
00126       // The emitter is always called KPIM::IMAPCompletionOrder by contract
00127       if ( !connectDCOPSignal( 0, "KPIM::IMAPCompletionOrder", "orderChanged()",
00128             "slotIMAPCompletionOrderChanged()", false ) )
00129         kdError() << "AddresseeLineEdit: connection to orderChanged() failed" << endl;
00130 
00131       connect( s_LDAPTimer, SIGNAL( timeout() ), SLOT( slotStartLDAPLookup() ) );
00132       connect( s_LDAPSearch, SIGNAL( searchData( const KPIM::LdapResultList& ) ),
00133           SLOT( slotLDAPSearchData( const KPIM::LdapResultList& ) ) );
00134 
00135       m_completionInitialized = true;
00136     }
00137   }
00138 }
00139 
00140 AddresseeLineEdit::~AddresseeLineEdit()
00141 {
00142   if ( s_LDAPSearch && s_LDAPLineEdit == this )
00143     stopLDAPLookup();
00144 }
00145 
00146 void AddresseeLineEdit::setFont( const QFont& font )
00147 {
00148   KLineEdit::setFont( font );
00149   if ( m_useCompletion )
00150     completionBox()->setFont( font );
00151 }
00152 
00153 void AddresseeLineEdit::keyPressEvent( QKeyEvent *e )
00154 {
00155   bool accept = false;
00156 
00157   if ( KStdAccel::shortcut( KStdAccel::SubstringCompletion ).contains( KKey( e ) ) ) {
00158     doCompletion( true );
00159     accept = true;
00160   } else if ( KStdAccel::shortcut( KStdAccel::TextCompletion ).contains( KKey( e ) ) ) {
00161     int len = text().length();
00162 
00163     if ( len == cursorPosition() ) { // at End?
00164       doCompletion( true );
00165       accept = true;
00166     }
00167   }
00168 
00169   if ( !accept )
00170     KLineEdit::keyPressEvent( e );
00171 
00172   if ( e->isAccepted() ) {
00173     if ( m_useCompletion && s_LDAPTimer != NULL ) {
00174       if ( *s_LDAPText != text() || s_LDAPLineEdit != this )
00175         stopLDAPLookup();
00176 
00177       *s_LDAPText = text();
00178       s_LDAPLineEdit = this;
00179       s_LDAPTimer->start( 500, true );
00180     }
00181   }
00182 }
00183 
00184 void AddresseeLineEdit::insert( const QString &t )
00185 {
00186   if ( !m_smartPaste ) {
00187     KLineEdit::insert( t );
00188     return;
00189   }
00190 
00191   //kdDebug(5300) << "     AddresseeLineEdit::insert( \"" << t << "\" )" << endl;
00192 
00193   QString newText = t.stripWhiteSpace();
00194   if ( newText.isEmpty() )
00195     return;
00196 
00197   // remove newlines in the to-be-pasted string as well as an eventual
00198   // mailto: protocol
00199   newText.replace( QRegExp("\r?\n"), ", " );
00200 
00201   if ( newText.startsWith("mailto:") ) {
00202     KURL url( newText );
00203     newText = url.path();
00204   }
00205   else if ( newText.find(" at ") != -1 ) {
00206     // Anti-spam stuff
00207     newText.replace( " at ", "@" );
00208     newText.replace( " dot ", "." );
00209   }
00210   else if ( newText.find("(at)") != -1 ) {
00211     newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
00212   }
00213 
00214   QString contents = text();
00215   int start_sel = 0;
00216   int end_sel = 0;
00217   int pos = cursorPosition();
00218   if ( getSelection( &start_sel, &end_sel ) ) {
00219     // Cut away the selection.
00220     if ( pos > end_sel )
00221       pos -= (end_sel - start_sel);
00222     else if ( pos > start_sel )
00223       pos = start_sel;
00224     contents = contents.left( start_sel ) + contents.right( end_sel + 1 );
00225   }
00226 
00227   int eot = contents.length();
00228   while ((eot > 0) && contents[ eot - 1 ].isSpace() ) eot--;
00229   if ( eot == 0 )
00230     contents = QString::null;
00231   else if ( pos >= eot ) {
00232     if ( contents[ eot - 1 ] == ',' )
00233       eot--;
00234     contents.truncate( eot );
00235     contents += ", ";
00236     pos = eot + 2;
00237   }
00238 
00239   contents = contents.left( pos ) + newText + contents.mid( pos );
00240   setText( contents );
00241   setCursorPosition( pos + newText.length() );
00242 }
00243 
00244 void AddresseeLineEdit::paste()
00245 {
00246   if ( m_useCompletion )
00247     m_smartPaste = true;
00248 
00249   KLineEdit::paste();
00250   m_smartPaste = false;
00251 }
00252 
00253 void AddresseeLineEdit::mouseReleaseEvent( QMouseEvent *e )
00254 {
00255   // reimplemented from QLineEdit::mouseReleaseEvent()
00256   if ( m_useCompletion
00257        && QApplication::clipboard()->supportsSelection()
00258        && !isReadOnly()
00259        && e->button() == MidButton ) {
00260     m_smartPaste = true;
00261   }
00262 
00263   KLineEdit::mouseReleaseEvent( e );
00264   m_smartPaste = false;
00265 }
00266 
00267 void AddresseeLineEdit::dropEvent( QDropEvent *e )
00268 {
00269   KURL::List uriList;
00270   if ( !isReadOnly()
00271        && KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
00272     QString contents = text();
00273     // remove trailing white space and comma
00274     int eot = contents.length();
00275     while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
00276       eot--;
00277     if ( eot == 0 )
00278       contents = QString::null;
00279     else if ( contents[ eot - 1 ] == ',' ) {
00280       eot--;
00281       contents.truncate( eot );
00282     }
00283     bool mailtoURL = false;
00284     // append the mailto URLs
00285     for ( KURL::List::Iterator it = uriList.begin();
00286           it != uriList.end(); ++it ) {
00287       if ( !contents.isEmpty() )
00288         contents.append( ", " );
00289       KURL u( *it );
00290       if ( u.protocol() == "mailto" ) {
00291         mailtoURL = true;
00292         contents.append( (*it).path() );
00293       }
00294     }
00295     if ( mailtoURL ) {
00296       setText( contents );
00297       setEdited( true );
00298       return;
00299     }
00300   }
00301 
00302   if ( m_useCompletion )
00303      m_smartPaste = true;
00304   QLineEdit::dropEvent( e );
00305   m_smartPaste = false;
00306 }
00307 
00308 void AddresseeLineEdit::cursorAtEnd()
00309 {
00310   setCursorPosition( text().length() );
00311 }
00312 
00313 void AddresseeLineEdit::enableCompletion( bool enable )
00314 {
00315   m_useCompletion = enable;
00316 }
00317 
00318 void AddresseeLineEdit::doCompletion( bool ctrlT )
00319 {
00320   if ( !m_useCompletion )
00321     return;
00322 
00323   if ( s_addressesDirty )
00324     loadContacts(); // read from local address book
00325 
00326   // cursor at end of string - or Ctrl+T pressed for substring completion?
00327   if ( ctrlT ) {
00328     const QStringList completions = s_completion->substringCompletion( m_searchString );
00329 
00330     if ( completions.count() > 1 )
00331       ; //m_previousAddresses = prevAddr;
00332     else if ( completions.count() == 1 )
00333       setText( m_previousAddresses + completions.first() );
00334 
00335     setCompletedItems( completions, true ); // this makes sure the completion popup is closed if no matching items were found
00336 
00337     cursorAtEnd();
00338     return;
00339   }
00340 
00341   KGlobalSettings::Completion  mode = completionMode();
00342 
00343   switch ( mode ) {
00344     case KGlobalSettings::CompletionPopupAuto:
00345     {
00346       if ( m_searchString.isEmpty() )
00347         break;
00348     }
00349 
00350     case KGlobalSettings::CompletionPopup:
00351     {
00352       //m_previousAddresses = prevAddr;
00353       QStringList items = s_completion->allMatches( m_searchString );
00354       items += s_completion->allMatches( "\"" + m_searchString );
00355       uint beforeDollarCompletionCount = items.count();
00356 
00357       if ( m_searchString.find( ' ' ) == -1 ) // one word, possibly given name
00358         items += s_completion->allMatches( "$$" + m_searchString );
00359 
00360       if ( items.isEmpty() ) {
00361         setCompletedItems( items, false );
00362       } else {
00363         if ( items.count() > beforeDollarCompletionCount ) {
00364           // remove the '$$whatever$' part
00365           for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
00366             int pos = (*it).find( '$', 2 );
00367             if ( pos < 0 ) // ???
00368               continue;
00369             (*it) = (*it).mid( pos + 1 );
00370           }
00371         }
00372 
00373         bool autoSuggest = (mode != KGlobalSettings::CompletionPopupAuto);
00374         setCompletedItems( items, autoSuggest );
00375 
00376         if ( !autoSuggest ) {
00377           int index = items.first().find( m_searchString );
00378           QString newText = m_previousAddresses + items.first().mid( index );
00379           setUserSelection( false );
00380           setCompletedText( newText, true );
00381         }
00382       }
00383 
00384       break;
00385     }
00386 
00387     case KGlobalSettings::CompletionShell:
00388     {
00389       QString match = s_completion->makeCompletion( m_searchString );
00390       if ( !match.isNull() && match != m_searchString ) {
00391         setText( m_previousAddresses + match );
00392         cursorAtEnd();
00393       }
00394       break;
00395     }
00396 
00397     case KGlobalSettings::CompletionMan: // Short-Auto in fact
00398     case KGlobalSettings::CompletionAuto:
00399     {
00400       if ( !m_searchString.isEmpty() ) {
00401         QString match = s_completion->makeCompletion( m_searchString );
00402         if ( !match.isNull() && match != m_searchString ) {
00403           QString adds = m_previousAddresses + match;
00404           setCompletedText( adds );
00405         }
00406         break;
00407       }
00408     }
00409 
00410     case KGlobalSettings::CompletionNone:
00411     default: // fall through
00412       break;
00413   }
00414 }
00415 
00416 void AddresseeLineEdit::slotPopupCompletion( const QString& completion )
00417 {
00418   setText( m_previousAddresses + completion );
00419   cursorAtEnd();
00420 //  slotMatched( m_previousAddresses + completion );
00421 }
00422 
00423 void AddresseeLineEdit::loadContacts()
00424 {
00425   s_completion->clear();
00426   s_addressesDirty = false;
00427   //m_contactMap.clear();
00428 
00429   QApplication::setOverrideCursor( KCursor::waitCursor() ); // loading might take a while
00430 
00431   KConfig config( "kpimcompletionorder" ); // The weights for non-imap kabc resources is there.
00432   config.setGroup( "CompletionWeights" );
00433 
00434   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00435   // Can't just use the addressbook's iterator, we need to know which subresource
00436   // is behind which contact.
00437   QPtrList<KABC::Resource> resources( addressBook->resources() );
00438   for( QPtrListIterator<KABC::Resource> resit( resources ); *resit; ++resit ) {
00439     KABC::Resource* resource = *resit;
00440     KPIM::ResourceABC* resabc = dynamic_cast<ResourceABC *>( resource );
00441     if ( resabc ) { // IMAP KABC resource; need to associate each contact with the subresource
00442       const QMap<QString, QString> uidToResourceMap = resabc->uidToResourceMap();
00443       KABC::Resource::Iterator it;
00444       for ( it = resource->begin(); it != resource->end(); ++it ) {
00445         QString uid = (*it).uid();
00446         QMap<QString, QString>::const_iterator wit = uidToResourceMap.find( uid );
00447         int weight = ( wit != uidToResourceMap.end() ) ? resabc->subresourceCompletionWeight( *wit ) : 80;
00448         //kdDebug(5300) << (*it).fullEmail() << " subres=" << *wit << " weight=" << weight << endl;
00449         addContact( *it, weight );
00450       }
00451     } else { // KABC non-imap resource
00452       int weight = config.readNumEntry( resource->identifier(), 60 );
00453       KABC::Resource::Iterator it;
00454       for ( it = resource->begin(); it != resource->end(); ++it )
00455         addContact( *it, weight );
00456     }
00457   }
00458 
00459   int weight = config.readNumEntry( "DistributionLists", 60 );
00460   KABC::DistributionListManager manager( addressBook );
00461   manager.load();
00462   const QStringList distLists = manager.listNames();
00463   QStringList::const_iterator listIt;
00464   for ( listIt = distLists.begin(); listIt != distLists.end(); ++listIt ) {
00465     s_completion->addItem( (*listIt).simplifyWhiteSpace(), weight );
00466   }
00467 
00468   QApplication::restoreOverrideCursor();
00469 
00470   if ( !m_addressBookConnected ) {
00471     connect( addressBook, SIGNAL( addressBookChanged( AddressBook* ) ), SLOT( loadContacts() ) );
00472     m_addressBookConnected = true;
00473   }
00474 }
00475 
00476 void AddresseeLineEdit::addContact( const KABC::Addressee& addr, int weight )
00477 {
00478   //m_contactMap.insert( addr.realName(), addr );
00479   const QStringList emails = addr.emails();
00480   QStringList::ConstIterator it;
00481   for ( it = emails.begin(); it != emails.end(); ++it ) {
00482     int len = (*it).length();
00483     if ( len == 0 ) continue;
00484     if( '\0' == (*it)[len-1] )
00485       --len;
00486     const QString tmp = (*it).left( len );
00487     //kdDebug(5300) << "     AddresseeLineEdit::addContact() \"" << tmp << "\"" << endl;
00488     QString fullEmail = addr.fullEmail( tmp );
00489     //kdDebug(5300) << "                                     \"" << fullEmail << "\"" << endl;
00490     s_completion->addItem( fullEmail.simplifyWhiteSpace(), weight );
00491   }
00492 }
00493 
00494 void AddresseeLineEdit::slotStartLDAPLookup()
00495 {
00496   if ( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
00497     return;
00498 
00499   startLoadingLDAPEntries();
00500 }
00501 
00502 void AddresseeLineEdit::stopLDAPLookup()
00503 {
00504   s_LDAPSearch->cancelSearch();
00505   s_LDAPLineEdit = NULL;
00506 }
00507 
00508 void AddresseeLineEdit::startLoadingLDAPEntries()
00509 {
00510   QString s( *s_LDAPText );
00511   // TODO cache last?
00512   QString prevAddr;
00513   int n = s.findRev( ',' );
00514   if ( n >= 0 ) {
00515     prevAddr = s.left( n + 1 ) + ' ';
00516     s = s.mid( n + 1, 255 ).stripWhiteSpace();
00517   }
00518 
00519   if ( s.isEmpty() )
00520     return;
00521 
00522   loadContacts(); // TODO reuse these?
00523   s_LDAPSearch->startSearch( s );
00524 }
00525 
00526 void AddresseeLineEdit::slotLDAPSearchData( const KPIM::LdapResultList& adrs )
00527 {
00528   if ( s_LDAPLineEdit != this )
00529     return;
00530 
00531   for ( KPIM::LdapResultList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
00532     KABC::Addressee addr;
00533     addr.setNameFromString( (*it).name );
00534     addr.setEmails( (*it).email );
00535     addContact( addr, (*it).completionWeight );
00536   }
00537 
00538   if ( hasFocus() || completionBox()->hasFocus() )
00539     if ( completionMode() != KGlobalSettings::CompletionNone )
00540       doCompletion( false );
00541 }
00542 
00543 void AddresseeLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
00544 {
00545     KCompletionBox* completionBox = this->completionBox();
00546 
00547     if ( !items.isEmpty() &&
00548          !(items.count() == 1 && m_searchString == items.first()) )
00549     {
00550         if ( completionBox->isVisible() )
00551         {
00552           bool wasSelected = completionBox->isSelected( completionBox->currentItem() );
00553           const QString currentSelection = completionBox->currentText();
00554           completionBox->setItems( items );
00555           QListBoxItem* item = completionBox->findItem( currentSelection, Qt::ExactMatch );
00556           if ( item )
00557           {
00558             completionBox->blockSignals( true );
00559             completionBox->setCurrentItem( item );
00560             completionBox->setSelected( item, wasSelected );
00561             completionBox->blockSignals( false );
00562           }
00563         }
00564         else // completion box not visible yet -> show it
00565         {
00566           if ( !m_searchString.isEmpty() )
00567             completionBox->setCancelledText( m_searchString );
00568           completionBox->setItems( items );
00569           completionBox->popup();
00570         }
00571 
00572         if ( autoSuggest )
00573         {
00574             int index = items.first().find( m_searchString );
00575             QString newText = items.first().mid( index );
00576             setUserSelection(false);
00577             setCompletedText(newText,true);
00578         }
00579     }
00580     else
00581     {
00582         if ( completionBox && completionBox->isVisible() )
00583             completionBox->hide();
00584     }
00585 }
00586 
00587 QPopupMenu* AddresseeLineEdit::createPopupMenu()
00588 {
00589   QPopupMenu *menu = KLineEdit::createPopupMenu();
00590   if ( !menu )
00591     return 0;
00592 
00593   if ( m_useCompletion )
00594     menu->insertItem( i18n( "Edit Completion Order..." ),
00595                       this, SLOT( slotEditCompletionOrder() ) );
00596   return menu;
00597 }
00598 
00599 void AddresseeLineEdit::slotEditCompletionOrder()
00600 {
00601   init(); // for s_LDAPSearch
00602   CompletionOrderEditor editor( s_LDAPSearch, this );
00603   editor.exec();
00604 }
00605 
00606 KConfig* AddresseeLineEdit::config()
00607 {
00608   if ( !s_config )
00609     configDeleter.setObject( s_config, new KConfig( locateLocal( "config",
00610                              "kabldaprc" ) ) );
00611 
00612   return s_config;
00613 }
00614 
00615 void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
00616 {
00617   if ( m_useCompletion )
00618     s_addressesDirty = true;
00619 }
00620 
00621 void KPIM::AddresseeLineEdit::slotUserCancelled( const QString& cancelText )
00622 {
00623   if ( s_LDAPSearch && s_LDAPLineEdit == this )
00624     stopLDAPLookup();
00625   userCancelled( cancelText ); // in KLineEdit
00626 }
00627 
00628 void KPIM::AddresseeLineEdit::slotCompletion()
00629 {
00630   // Called by KLineEdit's keyPressEvent -> new text, update search string
00631   m_searchString = text();
00632   int n = m_searchString.findRev(',');
00633   if ( n >= 0 ) {
00634     ++n; // Go past the ","
00635 
00636     int len = m_searchString.length();
00637 
00638     // Increment past any whitespace...
00639     while ( n < len && m_searchString[ n ].isSpace() )
00640       ++n;
00641 
00642     m_previousAddresses = m_searchString.left( n );
00643     m_searchString = m_searchString.mid( n ).stripWhiteSpace();
00644   }
00645   else
00646   {
00647     m_previousAddresses = QString::null;
00648   }
00649   doCompletion( false );
00650 }
00651 
00652 #include "addresseelineedit.moc"
KDE Logo
This file is part of the documentation for libkdepim Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Apr 4 06:42:18 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003