00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "addresseelineedit.h"
00028
00029 #include <kabc/distributionlist.h>
00030 #include <kabc/stdaddressbook.h>
00031 #include <kabc/resource.h>
00032
00033 #include <kcompletionbox.h>
00034 #include <kcursor.h>
00035 #include <kdebug.h>
00036 #include <kstandarddirs.h>
00037 #include <kstaticdeleter.h>
00038 #include <kstdaccel.h>
00039 #include <kurldrag.h>
00040 #include <klocale.h>
00041
00042 #include "completionordereditor.h"
00043 #include "ldapclient.h"
00044
00045 #include <qpopupmenu.h>
00046 #include <qapplication.h>
00047 #include <qobject.h>
00048 #include <qptrlist.h>
00049 #include <qregexp.h>
00050 #include <qevent.h>
00051 #include <qdragobject.h>
00052 #include <qclipboard.h>
00053 #include "resourceabc.h"
00054 #include "distributionlist.h"
00055
00056 using namespace KPIM;
00057
00058 KCompletion * AddresseeLineEdit::s_completion = 0L;
00059 KPIM::CompletionItemsMap* AddresseeLineEdit::s_completionItemMap = 0L;
00060 QStringList* AddresseeLineEdit::s_completionSources = 0L;
00061 bool AddresseeLineEdit::s_addressesDirty = false;
00062 QTimer* AddresseeLineEdit::s_LDAPTimer = 0L;
00063 KPIM::LdapSearch* AddresseeLineEdit::s_LDAPSearch = 0L;
00064 QString* AddresseeLineEdit::s_LDAPText = 0L;
00065 AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
00066
00067
00068 static KStaticDeleter<KCompletion> completionDeleter;
00069 static KStaticDeleter<KPIM::CompletionItemsMap> completionItemsDeleter;
00070 static KStaticDeleter<QTimer> ldapTimerDeleter;
00071 static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
00072 static KStaticDeleter<QString> ldapTextDeleter;
00073 static KStaticDeleter<KConfig> configDeleter;
00074 static KStaticDeleter<QStringList> completionSourcesDeleter;
00075
00076
00077 static QCString newLineEditDCOPObjectName()
00078 {
00079 static int s_count = 0;
00080 QCString name( "KPIM::AddresseeLineEdit" );
00081 if ( s_count++ ) {
00082 name += '-';
00083 name += QCString().setNum( s_count );
00084 }
00085 return name;
00086 }
00087
00088 static const QString s_completionItemIndentString = " ";
00089
00090 AddresseeLineEdit::AddresseeLineEdit( QWidget* parent, bool useCompletion,
00091 const char *name )
00092 : ClickLineEdit( parent, QString::null, name ), DCOPObject( newLineEditDCOPObjectName() )
00093 {
00094 m_useCompletion = useCompletion;
00095 m_completionInitialized = false;
00096 m_smartPaste = false;
00097 m_addressBookConnected = false;
00098 init();
00099
00100 if ( m_useCompletion )
00101 s_addressesDirty = true;
00102 }
00103
00104
00105 void AddresseeLineEdit::init()
00106 {
00107 if ( !s_completion ) {
00108 completionDeleter.setObject( s_completion, new KCompletion() );
00109 s_completion->setOrder( completionOrder() );
00110 s_completion->setIgnoreCase( true );
00111
00112 completionItemsDeleter.setObject( s_completionItemMap, new KPIM::CompletionItemsMap() );
00113 completionSourcesDeleter.setObject( s_completionSources, new QStringList() );
00114 }
00115
00116
00117
00118
00119 if ( m_useCompletion ) {
00120 if ( !s_LDAPTimer ) {
00121 ldapTimerDeleter.setObject( s_LDAPTimer, new QTimer );
00122 ldapSearchDeleter.setObject( s_LDAPSearch, new KPIM::LdapSearch );
00123 ldapTextDeleter.setObject( s_LDAPText, new QString );
00124
00125
00126
00127 QValueList< LdapClient* > clients = s_LDAPSearch->clients();
00128 for ( QValueList<LdapClient*>::iterator it = clients.begin(); it != clients.end(); ++it ) {
00129 addCompletionSource( "LDAP server: " + (*it)->host() );
00130 }
00131 }
00132 if ( !m_completionInitialized ) {
00133 setCompletionObject( s_completion, false );
00134 connect( this, SIGNAL( completion( const QString& ) ),
00135 this, SLOT( slotCompletion() ) );
00136
00137 KCompletionBox *box = completionBox();
00138 connect( box, SIGNAL( highlighted( const QString& ) ),
00139 this, SLOT( slotPopupCompletion( const QString& ) ) );
00140 connect( box, SIGNAL( userCancelled( const QString& ) ),
00141 SLOT( slotUserCancelled( const QString& ) ) );
00142
00143
00144 if ( !connectDCOPSignal( 0, "KPIM::IMAPCompletionOrder", "orderChanged()",
00145 "slotIMAPCompletionOrderChanged()", false ) )
00146 kdError() << "AddresseeLineEdit: connection to orderChanged() failed" << endl;
00147
00148 connect( s_LDAPTimer, SIGNAL( timeout() ), SLOT( slotStartLDAPLookup() ) );
00149 connect( s_LDAPSearch, SIGNAL( searchData( const KPIM::LdapResultList& ) ),
00150 SLOT( slotLDAPSearchData( const KPIM::LdapResultList& ) ) );
00151
00152 m_completionInitialized = true;
00153 }
00154 }
00155 }
00156
00157 AddresseeLineEdit::~AddresseeLineEdit()
00158 {
00159 if ( s_LDAPSearch && s_LDAPLineEdit == this )
00160 stopLDAPLookup();
00161 }
00162
00163 void AddresseeLineEdit::setFont( const QFont& font )
00164 {
00165 KLineEdit::setFont( font );
00166 if ( m_useCompletion )
00167 completionBox()->setFont( font );
00168 }
00169
00170 void AddresseeLineEdit::allowSemiColonAsSeparator( bool useSemiColonAsSeparator )
00171 {
00172 m_useSemiColonAsSeparator = useSemiColonAsSeparator;
00173 }
00174
00175 void AddresseeLineEdit::keyPressEvent( QKeyEvent *e )
00176 {
00177 bool accept = false;
00178
00179 if ( KStdAccel::shortcut( KStdAccel::SubstringCompletion ).contains( KKey( e ) ) ) {
00180 doCompletion( true );
00181 accept = true;
00182 } else if ( KStdAccel::shortcut( KStdAccel::TextCompletion ).contains( KKey( e ) ) ) {
00183 int len = text().length();
00184
00185 if ( len == cursorPosition() ) {
00186 doCompletion( true );
00187 accept = true;
00188 }
00189 }
00190
00191 if ( !accept )
00192 KLineEdit::keyPressEvent( e );
00193
00194 if ( e->isAccepted() ) {
00195 if ( m_useCompletion && s_LDAPTimer != NULL ) {
00196 if ( *s_LDAPText != text() || s_LDAPLineEdit != this )
00197 stopLDAPLookup();
00198
00199 *s_LDAPText = text();
00200 s_LDAPLineEdit = this;
00201 s_LDAPTimer->start( 500, true );
00202 }
00203 }
00204 }
00205
00206 void AddresseeLineEdit::insert( const QString &t )
00207 {
00208 if ( !m_smartPaste ) {
00209 KLineEdit::insert( t );
00210 return;
00211 }
00212
00213 kdDebug(5300) << " AddresseeLineEdit::insert( \"" << t << "\" )" << endl;
00214
00215 QString newText = t.stripWhiteSpace();
00216 if ( newText.isEmpty() )
00217 return;
00218
00219
00220 QStringList lines = QStringList::split( QRegExp("\r?\n"), newText, false );
00221 for ( QStringList::iterator it = lines.begin();
00222 it != lines.end(); ++it ) {
00223
00224 (*it).remove( QRegExp(",?\\s*$") );
00225 }
00226 newText = lines.join( ", " );
00227
00228 if ( newText.lower().startsWith("mailto:") ) {
00229 KURL url( newText );
00230 newText = url.path();
00231 }
00232 else if ( newText.find(" at ") != -1 ) {
00233
00234 newText.replace( " at ", "@" );
00235 newText.replace( " dot ", "." );
00236 }
00237 else if ( newText.find("(at)") != -1 ) {
00238 newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
00239 }
00240
00241 QString contents = text();
00242 int start_sel = 0;
00243 int end_sel = 0;
00244 int pos = cursorPosition();
00245 if ( getSelection( &start_sel, &end_sel ) ) {
00246
00247 if ( pos > end_sel )
00248 pos -= (end_sel - start_sel);
00249 else if ( pos > start_sel )
00250 pos = start_sel;
00251 contents = contents.left( start_sel ) + contents.right( end_sel + 1 );
00252 }
00253
00254 int eot = contents.length();
00255 while ((eot > 0) && contents[ eot - 1 ].isSpace() ) eot--;
00256 if ( eot == 0 )
00257 contents = QString::null;
00258 else if ( pos >= eot ) {
00259 if ( contents[ eot - 1 ] == ',' )
00260 eot--;
00261 contents.truncate( eot );
00262 contents += ", ";
00263 pos = eot + 2;
00264 }
00265
00266 contents = contents.left( pos ) + newText + contents.mid( pos );
00267 setText( contents );
00268 setCursorPosition( pos + newText.length() );
00269 }
00270
00271 void AddresseeLineEdit::setText( const QString & text )
00272 {
00273 ClickLineEdit::setText( text.stripWhiteSpace() );
00274 }
00275
00276 void AddresseeLineEdit::paste()
00277 {
00278 if ( m_useCompletion )
00279 m_smartPaste = true;
00280
00281 KLineEdit::paste();
00282 m_smartPaste = false;
00283 }
00284
00285 void AddresseeLineEdit::mouseReleaseEvent( QMouseEvent *e )
00286 {
00287
00288 if ( m_useCompletion
00289 && QApplication::clipboard()->supportsSelection()
00290 && !isReadOnly()
00291 && e->button() == MidButton ) {
00292 m_smartPaste = true;
00293 }
00294
00295 KLineEdit::mouseReleaseEvent( e );
00296 m_smartPaste = false;
00297 }
00298
00299 void AddresseeLineEdit::dropEvent( QDropEvent *e )
00300 {
00301 KURL::List uriList;
00302 if ( !isReadOnly()
00303 && KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
00304 QString contents = text();
00305
00306 int eot = contents.length();
00307 while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
00308 eot--;
00309 if ( eot == 0 )
00310 contents = QString::null;
00311 else if ( contents[ eot - 1 ] == ',' ) {
00312 eot--;
00313 contents.truncate( eot );
00314 }
00315 bool mailtoURL = false;
00316
00317 for ( KURL::List::Iterator it = uriList.begin();
00318 it != uriList.end(); ++it ) {
00319 if ( !contents.isEmpty() )
00320 contents.append( ", " );
00321 KURL u( *it );
00322 if ( u.protocol() == "mailto" ) {
00323 mailtoURL = true;
00324 contents.append( (*it).path() );
00325 }
00326 }
00327 if ( mailtoURL ) {
00328 setText( contents );
00329 setEdited( true );
00330 return;
00331 }
00332 }
00333
00334 if ( m_useCompletion )
00335 m_smartPaste = true;
00336 QLineEdit::dropEvent( e );
00337 m_smartPaste = false;
00338 }
00339
00340 void AddresseeLineEdit::cursorAtEnd()
00341 {
00342 setCursorPosition( text().length() );
00343 }
00344
00345 void AddresseeLineEdit::enableCompletion( bool enable )
00346 {
00347 m_useCompletion = enable;
00348 }
00349
00350 void AddresseeLineEdit::doCompletion( bool ctrlT )
00351 {
00352 if ( !m_useCompletion )
00353 return;
00354
00355 if ( s_addressesDirty ) {
00356 loadContacts();
00357 s_completion->setOrder( completionOrder() );
00358 }
00359
00360
00361 if ( ctrlT ) {
00362 const QStringList completions = getAdjustedCompletionItems( false );
00363
00364 if ( completions.count() > 1 )
00365 ;
00366 else if ( completions.count() == 1 )
00367 setText( m_previousAddresses + completions.first().stripWhiteSpace() );
00368
00369 setCompletedItems( completions, true );
00370
00371 cursorAtEnd();
00372 return;
00373 }
00374
00375 KGlobalSettings::Completion mode = completionMode();
00376
00377 switch ( mode ) {
00378 case KGlobalSettings::CompletionPopupAuto:
00379 {
00380 if ( m_searchString.isEmpty() )
00381 break;
00382 }
00383
00384 case KGlobalSettings::CompletionPopup:
00385 {
00386 const QStringList items = getAdjustedCompletionItems( true );
00387 bool autoSuggest = !items.isEmpty() && (mode != KGlobalSettings::CompletionPopupAuto);
00388 setCompletedItems( items, autoSuggest );
00389
00390 if ( !autoSuggest ) {
00391 int index = items.first().find( m_searchString );
00392 QString newText = m_previousAddresses + items.first().mid( index ).stripWhiteSpace();
00393 setUserSelection( false );
00394 setCompletedText( newText, true );
00395 }
00396 break;
00397 }
00398
00399 case KGlobalSettings::CompletionShell:
00400 {
00401 QString match = s_completion->makeCompletion( m_searchString );
00402 if ( !match.isNull() && match != m_searchString ) {
00403 setText( m_previousAddresses + match );
00404 cursorAtEnd();
00405 }
00406 break;
00407 }
00408
00409 case KGlobalSettings::CompletionMan:
00410 case KGlobalSettings::CompletionAuto:
00411 {
00412 if ( !m_searchString.isEmpty() ) {
00413 QString match = s_completion->makeCompletion( m_searchString );
00414 if ( !match.isNull() && match != m_searchString ) {
00415 QString adds = m_previousAddresses + match;
00416 setCompletedText( adds );
00417 }
00418 break;
00419 }
00420 }
00421
00422 case KGlobalSettings::CompletionNone:
00423 default:
00424 break;
00425 }
00426 }
00427
00428 void AddresseeLineEdit::slotPopupCompletion( const QString& completion )
00429 {
00430 setText( m_previousAddresses + completion.stripWhiteSpace() );
00431 cursorAtEnd();
00432
00433 }
00434
00435 void AddresseeLineEdit::loadContacts()
00436 {
00437 s_completion->clear();
00438 s_completionItemMap->clear();
00439 s_addressesDirty = false;
00440
00441
00442 QApplication::setOverrideCursor( KCursor::waitCursor() );
00443
00444 KConfig config( "kpimcompletionorder" );
00445 config.setGroup( "CompletionWeights" );
00446
00447 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00448
00449
00450 QPtrList<KABC::Resource> resources( addressBook->resources() );
00451 for( QPtrListIterator<KABC::Resource> resit( resources ); *resit; ++resit ) {
00452 KABC::Resource* resource = *resit;
00453 KPIM::ResourceABC* resabc = dynamic_cast<ResourceABC *>( resource );
00454 if ( resabc ) {
00455 const QMap<QString, QString> uidToResourceMap = resabc->uidToResourceMap();
00456 KABC::Resource::Iterator it;
00457 for ( it = resource->begin(); it != resource->end(); ++it ) {
00458 QString uid = (*it).uid();
00459 QMap<QString, QString>::const_iterator wit = uidToResourceMap.find( uid );
00460 const QString subresourceLabel = resabc->subresourceLabel( *wit );
00461 int idx = s_completionSources->findIndex( subresourceLabel );
00462 if ( idx == -1 ) {
00463 s_completionSources->append( subresourceLabel );
00464 idx = s_completionSources->size() -1;
00465 }
00466 int weight = ( wit != uidToResourceMap.end() ) ? resabc->subresourceCompletionWeight( *wit ) : 80;
00467
00468 addContact( *it, weight, idx );
00469 }
00470 } else {
00471 int weight = config.readNumEntry( resource->identifier(), 60 );
00472 s_completionSources->append( resource->resourceName() );
00473 KABC::Resource::Iterator it;
00474 for ( it = resource->begin(); it != resource->end(); ++it )
00475 addContact( *it, weight, s_completionSources->size()-1 );
00476 }
00477 }
00478
00479 #if 0 // now done as part of the normal contacts
00480 int weight = config.readNumEntry( "DistributionLists", 60 );
00481 KABC::DistributionListManager manager( addressBook );
00482 manager.load();
00483 const QStringList distLists = manager.listNames();
00484 QStringList::const_iterator listIt;
00485 for ( listIt = distLists.begin(); listIt != distLists.end(); ++listIt ) {
00486 s_completion->addItem( (*listIt).simplifyWhiteSpace(), weight );
00487 }
00488 #endif
00489
00490 QApplication::restoreOverrideCursor();
00491
00492 if ( !m_addressBookConnected ) {
00493 connect( addressBook, SIGNAL( addressBookChanged( AddressBook* ) ), SLOT( loadContacts() ) );
00494 m_addressBookConnected = true;
00495 }
00496 }
00497
00498 void AddresseeLineEdit::addContact( const KABC::Addressee& addr, int weight, int source )
00499 {
00500 if ( KPIM::DistributionList::isDistributionList( addr ) ) {
00501
00502 addCompletionItem( addr.formattedName(), weight, source );
00503 return;
00504 }
00505
00506 const QStringList emails = addr.emails();
00507 QStringList::ConstIterator it;
00508 for ( it = emails.begin(); it != emails.end(); ++it ) {
00509 int len = (*it).length();
00510 if ( len == 0 ) continue;
00511 if( '\0' == (*it)[len-1] )
00512 --len;
00513 const QString tmp = (*it).left( len );
00514 const QString fullEmail = addr.fullEmail( tmp );
00515
00516 addCompletionItem( fullEmail.simplifyWhiteSpace(), weight, source );
00517
00518
00519
00520 QString name( addr.realName().simplifyWhiteSpace() );
00521 if( name.endsWith("\"") )
00522 name.truncate( name.length()-1 );
00523 if( name.startsWith("\"") )
00524 name = name.mid( 1 );
00525
00526
00527 if ( !name.isEmpty() )
00528 addCompletionItem( addr.preferredEmail() + " (" + name + ")", weight, source );
00529
00530 bool bDone = false;
00531 int i = 1;
00532 do{
00533 i = name.findRev(' ');
00534 if( 1 < i ){
00535 QString sLastName( name.mid(i+1) );
00536 if( ! sLastName.isEmpty() &&
00537 2 <= sLastName.length() &&
00538 ! sLastName.endsWith(".") ){
00539 name.truncate( i );
00540 if( !name.isEmpty() ){
00541 sLastName.prepend( "\"" );
00542 sLastName.append( ", " + name + "\" <" );
00543 }
00544 QString sExtraEntry( sLastName );
00545 sExtraEntry.append( tmp.isEmpty() ? addr.preferredEmail() : tmp );
00546 sExtraEntry.append( ">" );
00547
00548 addCompletionItem( sExtraEntry.simplifyWhiteSpace(), weight, source );
00549 bDone = true;
00550 }
00551 }
00552 if( !bDone ){
00553 name.truncate( i );
00554 if( name.endsWith("\"") )
00555 name.truncate( name.length()-1 );
00556 }
00557 }while( 1 < i && !bDone );
00558 }
00559 }
00560
00561 void AddresseeLineEdit::addCompletionItem( const QString& string, int weight, int completionItemSource )
00562 {
00563
00564
00565 CompletionItemsMap::iterator it = s_completionItemMap->find( string );
00566 if ( it != s_completionItemMap->end() ) {
00567 weight = QMAX( ( *it ).first, weight );
00568 ( *it ).first = weight;
00569 } else {
00570 s_completionItemMap->insert( string, qMakePair( weight, completionItemSource ) );
00571 }
00572 s_completion->addItem( string, weight );
00573 }
00574
00575 void AddresseeLineEdit::slotStartLDAPLookup()
00576 {
00577 if ( !s_LDAPSearch->isAvailable() ) {
00578 return;
00579 }
00580 if ( s_LDAPLineEdit != this )
00581 return;
00582
00583 startLoadingLDAPEntries();
00584 }
00585
00586 void AddresseeLineEdit::stopLDAPLookup()
00587 {
00588 s_LDAPSearch->cancelSearch();
00589 s_LDAPLineEdit = NULL;
00590 }
00591
00592 void AddresseeLineEdit::startLoadingLDAPEntries()
00593 {
00594 QString s( *s_LDAPText );
00595
00596 QString prevAddr;
00597 int n = s.findRev( ',' );
00598 if ( n >= 0 ) {
00599 prevAddr = s.left( n + 1 ) + ' ';
00600 s = s.mid( n + 1, 255 ).stripWhiteSpace();
00601 }
00602
00603 if ( s.isEmpty() )
00604 return;
00605
00606 loadContacts();
00607 s_LDAPSearch->startSearch( s );
00608 }
00609
00610 void AddresseeLineEdit::slotLDAPSearchData( const KPIM::LdapResultList& adrs )
00611 {
00612 if ( s_LDAPLineEdit != this )
00613 return;
00614
00615 for ( KPIM::LdapResultList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
00616 KABC::Addressee addr;
00617 addr.setNameFromString( (*it).name );
00618 addr.setEmails( (*it).email );
00619
00620 addContact( addr, (*it).completionWeight, (*it ).clientNumber );
00621 }
00622
00623 if ( hasFocus() || completionBox()->hasFocus() )
00624 if ( completionMode() != KGlobalSettings::CompletionNone )
00625 doCompletion( false );
00626 }
00627
00628
00629
00630 class KCompletionBoxHack : public KCompletionBox
00631 {
00632 public:
00633 KCompletionBoxHack() : KCompletionBox( 0 ) {}
00634 void sizeAndPosition() { KCompletionBox::sizeAndPosition(); }
00635 };
00636
00637 void AddresseeLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
00638 {
00639 KCompletionBox* completionBox = this->completionBox();
00640
00641 if ( !items.isEmpty() &&
00642 !(items.count() == 1 && m_searchString == items.first()) )
00643 {
00644 if ( completionBox->isVisible() )
00645 {
00646 bool wasSelected = completionBox->isSelected( completionBox->currentItem() );
00647 const QString currentSelection = completionBox->currentText();
00648 completionBox->setItems( items );
00649 QListBoxItem* item = completionBox->findItem( currentSelection, Qt::ExactMatch );
00650 if ( item )
00651 {
00652 completionBox->blockSignals( true );
00653 completionBox->setCurrentItem( item );
00654 completionBox->setSelected( item, wasSelected );
00655 completionBox->blockSignals( false );
00656 } else {
00657 completionBox->clearSelection();
00658 }
00659
00660
00661 KCompletionBoxHack* hack = static_cast<KCompletionBoxHack *>( completionBox );
00662 hack->sizeAndPosition();
00663 }
00664 else
00665 {
00666 if ( !m_searchString.isEmpty() )
00667 completionBox->setCancelledText( m_searchString );
00668 completionBox->setItems( items );
00669 completionBox->popup();
00670
00671
00672
00673 if ( s_completion->order() == KCompletion::Weighted )
00674 qApp->installEventFilter( this );
00675 }
00676 if ( autoSuggest )
00677 {
00678 int index = items.first().find( m_searchString );
00679 QString newText = items.first().mid( index );
00680 setUserSelection(false);
00681 setCompletedText(newText,true);
00682 }
00683 }
00684 else
00685 {
00686 if ( completionBox && completionBox->isVisible() ) {
00687 completionBox->hide();
00688 }
00689 }
00690 }
00691
00692 QPopupMenu* AddresseeLineEdit::createPopupMenu()
00693 {
00694 QPopupMenu *menu = KLineEdit::createPopupMenu();
00695 if ( !menu )
00696 return 0;
00697
00698 if ( m_useCompletion )
00699 menu->insertItem( i18n( "Configure Completion Order..." ),
00700 this, SLOT( slotEditCompletionOrder() ) );
00701 return menu;
00702 }
00703
00704 void AddresseeLineEdit::slotEditCompletionOrder()
00705 {
00706 init();
00707 CompletionOrderEditor editor( s_LDAPSearch, this );
00708 editor.exec();
00709 }
00710
00711 #if 0
00712 KConfig* AddresseeLineEdit::config()
00713 {
00714 if ( !s_config )
00715 configDeleter.setObject( s_config, new KConfig( locateLocal( "config",
00716 "kabldaprc" ) ) );
00717
00718 return s_config;
00719 }
00720 #endif
00721
00722 void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
00723 {
00724 if ( m_useCompletion )
00725 s_addressesDirty = true;
00726 }
00727
00728 void KPIM::AddresseeLineEdit::slotUserCancelled( const QString& cancelText )
00729 {
00730 if ( s_LDAPSearch && s_LDAPLineEdit == this )
00731 stopLDAPLookup();
00732 userCancelled( cancelText );
00733 }
00734
00735 void KPIM::AddresseeLineEdit::slotCompletion()
00736 {
00737
00738 m_searchString = text();
00739
00740 int n = m_searchString.findRev(',');
00741 if( m_useSemiColonAsSeparator )
00742 n = QMAX( n, m_searchString.findRev(';') );
00743
00744 if ( n >= 0 ) {
00745 ++n;
00746
00747 int len = m_searchString.length();
00748
00749
00750 while ( n < len && m_searchString[ n ].isSpace() )
00751 ++n;
00752
00753 m_previousAddresses = m_searchString.left( n );
00754 m_searchString = m_searchString.mid( n ).stripWhiteSpace();
00755 }
00756 else
00757 {
00758 m_previousAddresses = QString::null;
00759 }
00760 if ( completionBox() )
00761 completionBox()->setCancelledText( m_searchString );
00762 doCompletion( false );
00763 }
00764
00765
00766 KCompletion::CompOrder KPIM::AddresseeLineEdit::completionOrder()
00767 {
00768 KConfig config( "kpimcompletionorder" );
00769 config.setGroup( "General" );
00770 const QString order = config.readEntry( "CompletionOrder", "Weighted" );
00771
00772 if ( order == "Weighted" )
00773 return KCompletion::Weighted;
00774 else
00775 return KCompletion::Sorted;
00776 }
00777
00778 int KPIM::AddresseeLineEdit::addCompletionSource( const QString &source )
00779 {
00780 s_completionSources->append( source );
00781 return s_completionSources->size()-1;
00782 }
00783
00784 bool KPIM::AddresseeLineEdit::eventFilter(QObject *obj, QEvent *e)
00785 {
00786 if ( obj == completionBox() ) {
00787 if ( e->type() == QEvent::MouseButtonPress
00788 || e->type() == QEvent::MouseMove
00789 || e->type() == QEvent::MouseButtonRelease ) {
00790 QMouseEvent* me = static_cast<QMouseEvent*>( e );
00791
00792 QListBoxItem *item = completionBox()->itemAt( me->pos() );
00793 if ( !item ) {
00794
00795
00796 bool eat = e->type() == QEvent::MouseMove;
00797 return eat;
00798 }
00799
00800
00801 if ( e->type() == QEvent::MouseButtonPress
00802 || me->state() & LeftButton || me->state() & MidButton
00803 || me->state() & RightButton ) {
00804 if ( !item->text().startsWith( s_completionItemIndentString ) ) {
00805 return true;
00806 } else {
00807
00808
00809
00810 completionBox()->setCurrentItem( item );
00811 completionBox()->setSelected( completionBox()->index( item ), true );
00812 if ( e->type() == QEvent::MouseMove )
00813 return true;
00814 }
00815 }
00816 }
00817 }
00818 if ( ( obj == this ) &&
00819 ( e->type() == QEvent::AccelOverride ) ) {
00820 QKeyEvent *ke = static_cast<QKeyEvent*>( e );
00821 if ( ke->key() == Key_Up || ke->key() == Key_Down || ke->key() == Key_Tab ) {
00822 ke->accept();
00823 return true;
00824 }
00825 }
00826 if ( ( obj == this ) &&
00827 ( e->type() == QEvent::KeyPress ) &&
00828 completionBox()->isVisible() ) {
00829 QKeyEvent *ke = static_cast<QKeyEvent*>( e );
00830 unsigned int currentIndex = completionBox()->currentItem();
00831 if ( ke->key() == Key_Up || ke->key() == Key_Backtab ) {
00832
00833
00834
00835 QListBoxItem *itemAbove = completionBox()->item( currentIndex - 1 );
00836 if ( itemAbove && !itemAbove->text().startsWith( s_completionItemIndentString ) ) {
00837
00838
00839 if ( currentIndex > 1 && completionBox()->item( currentIndex - 2 ) ) {
00840
00841 completionBox()->setCurrentItem( itemAbove->prev() );
00842 completionBox()->setSelected( currentIndex - 2, true );
00843 } else if ( currentIndex == 1 ) {
00844
00845
00846 completionBox()->ensureVisible( 0, 0 );
00847 completionBox()->setSelected( currentIndex, true );
00848 }
00849 return true;
00850 }
00851 } else if ( ke->key() == Key_Down || ke->key() == Key_Tab ) {
00852
00853
00854 QListBoxItem *itemBelow = completionBox()->item( currentIndex + 1 );
00855 if ( itemBelow && !itemBelow->text().startsWith( s_completionItemIndentString ) ) {
00856 if ( completionBox()->item( currentIndex + 2 ) ) {
00857
00858 completionBox()->setCurrentItem( itemBelow->next() );
00859 completionBox()->setSelected( currentIndex + 2, true );
00860 } else {
00861
00862 completionBox()->setSelected( currentIndex, true );
00863 }
00864 return true;
00865 }
00866
00867 if ( !itemBelow && currentIndex == 1 ) {
00868 completionBox()->setSelected( currentIndex, true );
00869 }
00870
00871
00872
00873 QListBoxItem *item = completionBox()->item( currentIndex );
00874 if ( item && !item->text().startsWith( s_completionItemIndentString ) ) {
00875 completionBox()->setSelected( currentIndex, true );
00876 }
00877 }
00878 }
00879 return ClickLineEdit::eventFilter( obj, e );
00880 }
00881
00882 const QStringList KPIM::AddresseeLineEdit::getAdjustedCompletionItems( bool fullSearch )
00883 {
00884 QStringList items = fullSearch ?
00885 s_completion->allMatches( m_searchString )
00886 : s_completion->substringCompletion( m_searchString );
00887 if ( fullSearch )
00888 items += s_completion->allMatches( "\"" + m_searchString );
00889 unsigned int beforeDollarCompletionCount = items.count();
00890
00891 if ( fullSearch && m_searchString.find( ' ' ) == -1 )
00892 items += s_completion->allMatches( "$$" + m_searchString );
00893
00894
00895
00896 int lastSourceIndex = -1;
00897 unsigned int i = 0;
00898 QMap<int, QStringList> sections;
00899 QStringList sortedItems;
00900 for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it, ++i ) {
00901 CompletionItemsMap::const_iterator cit = s_completionItemMap->find(*it);
00902 if ( cit == s_completionItemMap->end() )continue;
00903 int idx = (*cit).second;
00904 if ( s_completion->order() == KCompletion::Weighted ) {
00905 if ( lastSourceIndex == -1 || lastSourceIndex != idx ) {
00906 const QString sourceLabel( (*s_completionSources)[idx] );
00907 if ( sections.find(idx) == sections.end() ) {
00908 items.insert( it, sourceLabel );
00909 }
00910 lastSourceIndex = idx;
00911 }
00912 (*it) = (*it).prepend( s_completionItemIndentString );
00913 }
00914 sections[idx].append( *it );
00915
00916 if ( i > beforeDollarCompletionCount ) {
00917
00918 int pos = (*it).find( '$', 2 );
00919 if ( pos < 0 )
00920 continue;
00921 (*it) = (*it).mid( pos + 1 );
00922 }
00923 if ( s_completion->order() == KCompletion::Sorted ) {
00924 sortedItems.append( *it );
00925 }
00926 }
00927 if ( s_completion->order() == KCompletion::Weighted ) {
00928 for ( QMap<int, QStringList>::Iterator it( sections.begin() ), end( sections.end() ); it != end; ++it ) {
00929 sortedItems.append( (*s_completionSources)[it.key()] );
00930 for ( QStringList::Iterator sit( (*it).begin() ), send( (*it).end() ); sit != send; ++sit ) {
00931 sortedItems.append( *sit );
00932 }
00933 }
00934 } else {
00935 sortedItems.sort();
00936 }
00937 return sortedItems;
00938 }
00939 #include "addresseelineedit.moc"