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 KPIM::CompletionItemsMap* AddresseeLineEdit::s_completionItemMap = 0L;
00058 bool AddresseeLineEdit::s_addressesDirty = false;
00059 QTimer* AddresseeLineEdit::s_LDAPTimer = 0L;
00060 KPIM::LdapSearch* AddresseeLineEdit::s_LDAPSearch = 0L;
00061 QString* AddresseeLineEdit::s_LDAPText = 0L;
00062 AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
00063 KConfig *AddresseeLineEdit::s_config = 0L;
00064 
00065 static KStaticDeleter<KCompletion> completionDeleter;
00066 static KStaticDeleter<KPIM::CompletionItemsMap> completionItemsDeleter;
00067 static KStaticDeleter<QTimer> ldapTimerDeleter;
00068 static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
00069 static KStaticDeleter<QString> ldapTextDeleter;
00070 static KStaticDeleter<KConfig> configDeleter;
00071 
00072 // needs to be unique, but the actual name doesn't matter much
00073 static QCString newLineEditDCOPObjectName()
00074 {
00075     static int s_count = 0;
00076     QCString name( "KPIM::AddresseeLineEdit" );
00077     if ( s_count++ ) {
00078       name += '-';
00079       name += QCString().setNum( s_count );
00080     }
00081     return name;
00082 }
00083 
00084 AddresseeLineEdit::AddresseeLineEdit( QWidget* parent, bool useCompletion,
00085                                       const char *name )
00086   : ClickLineEdit( parent, QString::null, name ), DCOPObject( newLineEditDCOPObjectName() )
00087 {
00088   m_useCompletion = useCompletion;
00089   m_completionInitialized = false;
00090   m_smartPaste = false;
00091   m_addressBookConnected = false;
00092 
00093   init();
00094 
00095   if ( m_useCompletion )
00096     s_addressesDirty = true;
00097 }
00098 
00099 
00100 void AddresseeLineEdit::init()
00101 {
00102   if ( !s_completion ) {
00103     completionDeleter.setObject( s_completion, new KCompletion() );
00104     s_completion->setOrder( KCompletion::Weighted );
00105     s_completion->setIgnoreCase( true );
00106 
00107     completionItemsDeleter.setObject( s_completionItemMap, new KPIM::CompletionItemsMap() );
00108   }
00109 
00110 //  connect( s_completion, SIGNAL( match( const QString& ) ),
00111 //           this, SLOT( slotMatched( const QString& ) ) );
00112 
00113   if ( m_useCompletion ) {
00114     if ( !s_LDAPTimer ) {
00115       ldapTimerDeleter.setObject( s_LDAPTimer, new QTimer );
00116       ldapSearchDeleter.setObject( s_LDAPSearch, new KPIM::LdapSearch );
00117       ldapTextDeleter.setObject( s_LDAPText, new QString );
00118     }
00119     if ( !m_completionInitialized ) {
00120       setCompletionObject( s_completion, false );
00121       connect( this, SIGNAL( completion( const QString& ) ),
00122           this, SLOT( slotCompletion() ) );
00123 
00124       KCompletionBox *box = completionBox();
00125       connect( box, SIGNAL( highlighted( const QString& ) ),
00126           this, SLOT( slotPopupCompletion( const QString& ) ) );
00127       connect( box, SIGNAL( userCancelled( const QString& ) ),
00128           SLOT( slotUserCancelled( const QString& ) ) );
00129 
00130       // The emitter is always called KPIM::IMAPCompletionOrder by contract
00131       if ( !connectDCOPSignal( 0, "KPIM::IMAPCompletionOrder", "orderChanged()",
00132             "slotIMAPCompletionOrderChanged()", false ) )
00133         kdError() << "AddresseeLineEdit: connection to orderChanged() failed" << endl;
00134 
00135       connect( s_LDAPTimer, SIGNAL( timeout() ), SLOT( slotStartLDAPLookup() ) );
00136       connect( s_LDAPSearch, SIGNAL( searchData( const KPIM::LdapResultList& ) ),
00137           SLOT( slotLDAPSearchData( const KPIM::LdapResultList& ) ) );
00138 
00139       m_completionInitialized = true;
00140     }
00141   }
00142 }
00143 
00144 AddresseeLineEdit::~AddresseeLineEdit()
00145 {
00146   if ( s_LDAPSearch && s_LDAPLineEdit == this )
00147     stopLDAPLookup();
00148 }
00149 
00150 void AddresseeLineEdit::setFont( const QFont& font )
00151 {
00152   KLineEdit::setFont( font );
00153   if ( m_useCompletion )
00154     completionBox()->setFont( font );
00155 }
00156 
00157 void AddresseeLineEdit::keyPressEvent( QKeyEvent *e )
00158 {
00159   bool accept = false;
00160 
00161   if ( KStdAccel::shortcut( KStdAccel::SubstringCompletion ).contains( KKey( e ) ) ) {
00162     doCompletion( true );
00163     accept = true;
00164   } else if ( KStdAccel::shortcut( KStdAccel::TextCompletion ).contains( KKey( e ) ) ) {
00165     int len = text().length();
00166 
00167     if ( len == cursorPosition() ) { // at End?
00168       doCompletion( true );
00169       accept = true;
00170     }
00171   }
00172 
00173   if ( !accept )
00174     KLineEdit::keyPressEvent( e );
00175 
00176   if ( e->isAccepted() ) {
00177     if ( m_useCompletion && s_LDAPTimer != NULL ) {
00178       if ( *s_LDAPText != text() || s_LDAPLineEdit != this )
00179         stopLDAPLookup();
00180 
00181       *s_LDAPText = text();
00182       s_LDAPLineEdit = this;
00183       s_LDAPTimer->start( 500, true );
00184     }
00185   }
00186 }
00187 
00188 void AddresseeLineEdit::insert( const QString &t )
00189 {
00190   if ( !m_smartPaste ) {
00191     KLineEdit::insert( t );
00192     return;
00193   }
00194 
00195   //kdDebug(5300) << "     AddresseeLineEdit::insert( \"" << t << "\" )" << endl;
00196 
00197   QString newText = t.stripWhiteSpace();
00198   if ( newText.isEmpty() )
00199     return;
00200 
00201   // remove newlines in the to-be-pasted string as well as an eventual
00202   // mailto: protocol
00203   newText.replace( QRegExp("\r?\n"), ", " );
00204 
00205   if ( newText.startsWith("mailto:") ) {
00206     KURL url( newText );
00207     newText = url.path();
00208   }
00209   else if ( newText.find(" at ") != -1 ) {
00210     // Anti-spam stuff
00211     newText.replace( " at ", "@" );
00212     newText.replace( " dot ", "." );
00213   }
00214   else if ( newText.find("(at)") != -1 ) {
00215     newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
00216   }
00217 
00218   QString contents = text();
00219   int start_sel = 0;
00220   int end_sel = 0;
00221   int pos = cursorPosition();
00222   if ( getSelection( &start_sel, &end_sel ) ) {
00223     // Cut away the selection.
00224     if ( pos > end_sel )
00225       pos -= (end_sel - start_sel);
00226     else if ( pos > start_sel )
00227       pos = start_sel;
00228     contents = contents.left( start_sel ) + contents.right( end_sel + 1 );
00229   }
00230 
00231   int eot = contents.length();
00232   while ((eot > 0) && contents[ eot - 1 ].isSpace() ) eot--;
00233   if ( eot == 0 )
00234     contents = QString::null;
00235   else if ( pos >= eot ) {
00236     if ( contents[ eot - 1 ] == ',' )
00237       eot--;
00238     contents.truncate( eot );
00239     contents += ", ";
00240     pos = eot + 2;
00241   }
00242 
00243   contents = contents.left( pos ) + newText + contents.mid( pos );
00244   setText( contents );
00245   setCursorPosition( pos + newText.length() );
00246 }
00247 
00248 void AddresseeLineEdit::paste()
00249 {
00250   if ( m_useCompletion )
00251     m_smartPaste = true;
00252 
00253   KLineEdit::paste();
00254   m_smartPaste = false;
00255 }
00256 
00257 void AddresseeLineEdit::mouseReleaseEvent( QMouseEvent *e )
00258 {
00259   // reimplemented from QLineEdit::mouseReleaseEvent()
00260   if ( m_useCompletion
00261        && QApplication::clipboard()->supportsSelection()
00262        && !isReadOnly()
00263        && e->button() == MidButton ) {
00264     m_smartPaste = true;
00265   }
00266 
00267   KLineEdit::mouseReleaseEvent( e );
00268   m_smartPaste = false;
00269 }
00270 
00271 void AddresseeLineEdit::dropEvent( QDropEvent *e )
00272 {
00273   KURL::List uriList;
00274   if ( !isReadOnly()
00275        && KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
00276     QString contents = text();
00277     // remove trailing white space and comma
00278     int eot = contents.length();
00279     while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
00280       eot--;
00281     if ( eot == 0 )
00282       contents = QString::null;
00283     else if ( contents[ eot - 1 ] == ',' ) {
00284       eot--;
00285       contents.truncate( eot );
00286     }
00287     bool mailtoURL = false;
00288     // append the mailto URLs
00289     for ( KURL::List::Iterator it = uriList.begin();
00290           it != uriList.end(); ++it ) {
00291       if ( !contents.isEmpty() )
00292         contents.append( ", " );
00293       KURL u( *it );
00294       if ( u.protocol() == "mailto" ) {
00295         mailtoURL = true;
00296         contents.append( (*it).path() );
00297       }
00298     }
00299     if ( mailtoURL ) {
00300       setText( contents );
00301       setEdited( true );
00302       return;
00303     }
00304   }
00305 
00306   if ( m_useCompletion )
00307      m_smartPaste = true;
00308   QLineEdit::dropEvent( e );
00309   m_smartPaste = false;
00310 }
00311 
00312 void AddresseeLineEdit::cursorAtEnd()
00313 {
00314   setCursorPosition( text().length() );
00315 }
00316 
00317 void AddresseeLineEdit::enableCompletion( bool enable )
00318 {
00319   m_useCompletion = enable;
00320 }
00321 
00322 void AddresseeLineEdit::doCompletion( bool ctrlT )
00323 {
00324   if ( !m_useCompletion )
00325     return;
00326 
00327   if ( s_addressesDirty )
00328     loadContacts(); // read from local address book
00329 
00330   // cursor at end of string - or Ctrl+T pressed for substring completion?
00331   if ( ctrlT ) {
00332     const QStringList completions = s_completion->substringCompletion( m_searchString );
00333 
00334     if ( completions.count() > 1 )
00335       ; //m_previousAddresses = prevAddr;
00336     else if ( completions.count() == 1 )
00337       setText( m_previousAddresses + completions.first() );
00338 
00339     setCompletedItems( completions, true ); // this makes sure the completion popup is closed if no matching items were found
00340 
00341     cursorAtEnd();
00342     return;
00343   }
00344 
00345   KGlobalSettings::Completion  mode = completionMode();
00346 
00347   switch ( mode ) {
00348     case KGlobalSettings::CompletionPopupAuto:
00349     {
00350       if ( m_searchString.isEmpty() )
00351         break;
00352     }
00353 
00354     case KGlobalSettings::CompletionPopup:
00355     {
00356       //m_previousAddresses = prevAddr;
00357       QStringList items = s_completion->allMatches( m_searchString );
00358       items += s_completion->allMatches( "\"" + m_searchString );
00359       uint beforeDollarCompletionCount = items.count();
00360 
00361       if ( m_searchString.find( ' ' ) == -1 ) // one word, possibly given name
00362         items += s_completion->allMatches( "$$" + m_searchString );
00363 
00364       if ( items.isEmpty() ) {
00365         setCompletedItems( items, false );
00366       } else {
00367         if ( items.count() > beforeDollarCompletionCount ) {
00368           // remove the '$$whatever$' part
00369           for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
00370             int pos = (*it).find( '$', 2 );
00371             if ( pos < 0 ) // ???
00372               continue;
00373             (*it) = (*it).mid( pos + 1 );
00374           }
00375         }
00376 
00377         bool autoSuggest = (mode != KGlobalSettings::CompletionPopupAuto);
00378         setCompletedItems( items, autoSuggest );
00379 
00380         if ( !autoSuggest ) {
00381           int index = items.first().find( m_searchString );
00382           QString newText = m_previousAddresses + items.first().mid( index );
00383           setUserSelection( false );
00384           setCompletedText( newText, true );
00385         }
00386       }
00387 
00388       break;
00389     }
00390 
00391     case KGlobalSettings::CompletionShell:
00392     {
00393       QString match = s_completion->makeCompletion( m_searchString );
00394       if ( !match.isNull() && match != m_searchString ) {
00395         setText( m_previousAddresses + match );
00396         cursorAtEnd();
00397       }
00398       break;
00399     }
00400 
00401     case KGlobalSettings::CompletionMan: // Short-Auto in fact
00402     case KGlobalSettings::CompletionAuto:
00403     {
00404       if ( !m_searchString.isEmpty() ) {
00405         QString match = s_completion->makeCompletion( m_searchString );
00406         if ( !match.isNull() && match != m_searchString ) {
00407           QString adds = m_previousAddresses + match;
00408           setCompletedText( adds );
00409         }
00410         break;
00411       }
00412     }
00413 
00414     case KGlobalSettings::CompletionNone:
00415     default: // fall through
00416       break;
00417   }
00418 }
00419 
00420 void AddresseeLineEdit::slotPopupCompletion( const QString& completion )
00421 {
00422   setText( m_previousAddresses + completion );
00423   cursorAtEnd();
00424 //  slotMatched( m_previousAddresses + completion );
00425 }
00426 
00427 void AddresseeLineEdit::loadContacts()
00428 {
00429   s_completion->clear();
00430   s_addressesDirty = false;
00431   //m_contactMap.clear();
00432 
00433   QApplication::setOverrideCursor( KCursor::waitCursor() ); // loading might take a while
00434 
00435   KConfig config( "kpimcompletionorder" ); // The weights for non-imap kabc resources is there.
00436   config.setGroup( "CompletionWeights" );
00437 
00438   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00439   // Can't just use the addressbook's iterator, we need to know which subresource
00440   // is behind which contact.
00441   QPtrList<KABC::Resource> resources( addressBook->resources() );
00442   for( QPtrListIterator<KABC::Resource> resit( resources ); *resit; ++resit ) {
00443     KABC::Resource* resource = *resit;
00444     KPIM::ResourceABC* resabc = dynamic_cast<ResourceABC *>( resource );
00445     if ( resabc ) { // IMAP KABC resource; need to associate each contact with the subresource
00446       const QMap<QString, QString> uidToResourceMap = resabc->uidToResourceMap();
00447       KABC::Resource::Iterator it;
00448       for ( it = resource->begin(); it != resource->end(); ++it ) {
00449         QString uid = (*it).uid();
00450         QMap<QString, QString>::const_iterator wit = uidToResourceMap.find( uid );
00451         int weight = ( wit != uidToResourceMap.end() ) ? resabc->subresourceCompletionWeight( *wit ) : 80;
00452         //kdDebug(5300) << (*it).fullEmail() << " subres=" << *wit << " weight=" << weight << endl;
00453         addContact( *it, weight );
00454       }
00455     } else { // KABC non-imap resource
00456       int weight = config.readNumEntry( resource->identifier(), 60 );
00457       KABC::Resource::Iterator it;
00458       for ( it = resource->begin(); it != resource->end(); ++it )
00459         addContact( *it, weight );
00460     }
00461   }
00462 
00463   int weight = config.readNumEntry( "DistributionLists", 60 );
00464   KABC::DistributionListManager manager( addressBook );
00465   manager.load();
00466   const QStringList distLists = manager.listNames();
00467   QStringList::const_iterator listIt;
00468   for ( listIt = distLists.begin(); listIt != distLists.end(); ++listIt ) {
00469     s_completion->addItem( (*listIt).simplifyWhiteSpace(), weight );
00470   }
00471 
00472   QApplication::restoreOverrideCursor();
00473 
00474   if ( !m_addressBookConnected ) {
00475     connect( addressBook, SIGNAL( addressBookChanged( AddressBook* ) ), SLOT( loadContacts() ) );
00476     m_addressBookConnected = true;
00477   }
00478 }
00479 
00480 void AddresseeLineEdit::addContact( const KABC::Addressee& addr, int weight )
00481 {
00482   //m_contactMap.insert( addr.realName(), addr );
00483   const QStringList emails = addr.emails();
00484   QStringList::ConstIterator it;
00485   for ( it = emails.begin(); it != emails.end(); ++it ) {
00486     int len = (*it).length();
00487     if ( len == 0 ) continue;
00488     if( '\0' == (*it)[len-1] )
00489       --len;
00490     const QString tmp = (*it).left( len );
00491     const QString fullEmail = addr.fullEmail( tmp );
00492     //kdDebug(5300) << "AddresseeLineEdit::addContact() \"" << fullEmail << "\" weight=" << weight << endl;
00493     addCompletionItem( fullEmail.simplifyWhiteSpace(), weight );
00494     // Try to guess the last name: if found, we add an extra
00495     // entry to the list to make sure completion works even
00496     // if the user starts by typing in the last name.
00497     QString name( addr.realName().simplifyWhiteSpace() );
00498     if( name.endsWith("\"") )
00499       name.truncate( name.length()-1 );
00500     if( name.startsWith("\"") )
00501       name = name.mid( 1 );
00502 
00503     // While we're here also add "email (full name)" for completion on the email
00504     if ( !name.isEmpty() )
00505       addCompletionItem( addr.preferredEmail() + " (" + name + ")", weight );
00506 
00507     bool bDone = false;
00508     int i = 1;
00509     do{
00510       i = name.findRev(' ');
00511       if( 1 < i ){
00512         QString sLastName( name.mid(i+1) );
00513         if( ! sLastName.isEmpty() &&
00514             2 <= sLastName.length() &&   // last names must be at least 2 chars long
00515             ! sLastName.endsWith(".") ){ // last names must not end with a dot (like "Jr." or "Sr.")
00516           name.truncate( i );
00517           if( !name.isEmpty() ){
00518             sLastName.prepend( "\"" );
00519             sLastName.append( ", " + name + "\" <" );
00520           }
00521           QString sExtraEntry( sLastName );
00522           sExtraEntry.append( tmp.isEmpty() ? addr.preferredEmail() : tmp );
00523           sExtraEntry.append( ">" );
00524           //kdDebug(5300) << "AddresseeLineEdit::addContact() added extra \"" << sExtraEntry.simplifyWhiteSpace() << "\" weight=" << weight << endl;
00525           addCompletionItem( sExtraEntry.simplifyWhiteSpace(), weight );
00526           bDone = true;
00527         }
00528       }
00529       if( !bDone ){
00530         name.truncate( i );
00531         if( name.endsWith("\"") )
00532           name.truncate( name.length()-1 );
00533       }
00534     }while( 1 < i && !bDone );
00535   }
00536 }
00537 
00538 void AddresseeLineEdit::addCompletionItem( const QString& string, int weight )
00539 {
00540   // Check if there is an exact match for item already, and use the max weight if so.
00541   // Since there's no way to get the information from KCompletion, we have to keep our own QMap
00542   CompletionItemsMap::iterator it = s_completionItemMap->begin();
00543   if ( it != s_completionItemMap->end() ) {
00544     weight = QMAX( *it, weight );
00545     *it = weight;
00546   } else {
00547     s_completionItemMap->insert( string, weight );
00548   }
00549 
00550   s_completion->addItem( string, weight );
00551 }
00552 
00553 void AddresseeLineEdit::slotStartLDAPLookup()
00554 {
00555   if ( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
00556     return;
00557 
00558   startLoadingLDAPEntries();
00559 }
00560 
00561 void AddresseeLineEdit::stopLDAPLookup()
00562 {
00563   s_LDAPSearch->cancelSearch();
00564   s_LDAPLineEdit = NULL;
00565   s_completionItemMap->clear();
00566 }
00567 
00568 void AddresseeLineEdit::startLoadingLDAPEntries()
00569 {
00570   QString s( *s_LDAPText );
00571   // TODO cache last?
00572   QString prevAddr;
00573   int n = s.findRev( ',' );
00574   if ( n >= 0 ) {
00575     prevAddr = s.left( n + 1 ) + ' ';
00576     s = s.mid( n + 1, 255 ).stripWhiteSpace();
00577   }
00578 
00579   if ( s.isEmpty() )
00580     return;
00581 
00582   loadContacts(); // TODO reuse these?
00583   s_LDAPSearch->startSearch( s );
00584 }
00585 
00586 void AddresseeLineEdit::slotLDAPSearchData( const KPIM::LdapResultList& adrs )
00587 {
00588   if ( s_LDAPLineEdit != this )
00589     return;
00590 
00591   for ( KPIM::LdapResultList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
00592     KABC::Addressee addr;
00593     addr.setNameFromString( (*it).name );
00594     addr.setEmails( (*it).email );
00595     addContact( addr, (*it).completionWeight );
00596   }
00597 
00598   if ( hasFocus() || completionBox()->hasFocus() )
00599     if ( completionMode() != KGlobalSettings::CompletionNone )
00600       doCompletion( false );
00601 }
00602 
00603 void AddresseeLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
00604 {
00605     KCompletionBox* completionBox = this->completionBox();
00606 
00607     if ( !items.isEmpty() &&
00608          !(items.count() == 1 && m_searchString == items.first()) )
00609     {
00610         if ( completionBox->isVisible() )
00611         {
00612           bool wasSelected = completionBox->isSelected( completionBox->currentItem() );
00613           const QString currentSelection = completionBox->currentText();
00614           completionBox->setItems( items );
00615           QListBoxItem* item = completionBox->findItem( currentSelection, Qt::ExactMatch );
00616           if ( item )
00617           {
00618             completionBox->blockSignals( true );
00619             completionBox->setCurrentItem( item );
00620             completionBox->setSelected( item, wasSelected );
00621             completionBox->blockSignals( false );
00622           }
00623         }
00624         else // completion box not visible yet -> show it
00625         {
00626           if ( !m_searchString.isEmpty() )
00627             completionBox->setCancelledText( m_searchString );
00628           completionBox->setItems( items );
00629           completionBox->popup();
00630         }
00631 
00632         if ( autoSuggest )
00633         {
00634             int index = items.first().find( m_searchString );
00635             QString newText = items.first().mid( index );
00636             setUserSelection(false);
00637             setCompletedText(newText,true);
00638         }
00639     }
00640     else
00641     {
00642         if ( completionBox && completionBox->isVisible() )
00643             completionBox->hide();
00644     }
00645 }
00646 
00647 QPopupMenu* AddresseeLineEdit::createPopupMenu()
00648 {
00649   QPopupMenu *menu = KLineEdit::createPopupMenu();
00650   if ( !menu )
00651     return 0;
00652 
00653   if ( m_useCompletion )
00654     menu->insertItem( i18n( "Edit Completion Order..." ),
00655                       this, SLOT( slotEditCompletionOrder() ) );
00656   return menu;
00657 }
00658 
00659 void AddresseeLineEdit::slotEditCompletionOrder()
00660 {
00661   init(); // for s_LDAPSearch
00662   CompletionOrderEditor editor( s_LDAPSearch, this );
00663   editor.exec();
00664 }
00665 
00666 KConfig* AddresseeLineEdit::config()
00667 {
00668   if ( !s_config )
00669     configDeleter.setObject( s_config, new KConfig( locateLocal( "config",
00670                              "kabldaprc" ) ) );
00671 
00672   return s_config;
00673 }
00674 
00675 void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
00676 {
00677   if ( m_useCompletion )
00678     s_addressesDirty = true;
00679 }
00680 
00681 void KPIM::AddresseeLineEdit::slotUserCancelled( const QString& cancelText )
00682 {
00683   if ( s_LDAPSearch && s_LDAPLineEdit == this )
00684     stopLDAPLookup();
00685   userCancelled( cancelText ); // in KLineEdit
00686 }
00687 
00688 void KPIM::AddresseeLineEdit::slotCompletion()
00689 {
00690   // Called by KLineEdit's keyPressEvent -> new text, update search string
00691   m_searchString = text();
00692   int n = m_searchString.findRev(',');
00693   if ( n >= 0 ) {
00694     ++n; // Go past the ","
00695 
00696     int len = m_searchString.length();
00697 
00698     // Increment past any whitespace...
00699     while ( n < len && m_searchString[ n ].isSpace() )
00700       ++n;
00701 
00702     m_previousAddresses = m_searchString.left( n );
00703     m_searchString = m_searchString.mid( n ).stripWhiteSpace();
00704   }
00705   else
00706   {
00707     m_previousAddresses = QString::null;
00708   }
00709   doCompletion( false );
00710 }
00711 
00712 #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 04:46:32 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003