26 #include "addresseelineedit.h"
28 #include "resourceabc.h"
29 #include "completionordereditor.h"
30 #include "ldapclient.h"
34 #ifdef TDEPIM_NEW_DISTRLISTS
35 #include "distributionlist.h"
37 #include <tdeabc/distributionlist.h>
40 #include <tdeabc/stdaddressbook.h>
41 #include <tdeabc/resource.h>
42 #include <libemailfunctions/email.h>
44 #include <tdecompletionbox.h>
47 #include <kstandarddirs.h>
48 #include <kstaticdeleter.h>
49 #include <tdestdaccel.h>
51 #include <tdelocale.h>
53 #include <tqpopupmenu.h>
54 #include <tqapplication.h>
56 #include <tqptrlist.h>
59 #include <tqdragobject.h>
60 #include <tqclipboard.h>
65 KPIM::CompletionItemsMap* AddresseeLineEdit::s_completionItemMap = 0L;
66 TQStringList* AddresseeLineEdit::s_completionSources = 0L;
67 bool AddresseeLineEdit::s_addressesDirty =
false;
68 TQTimer* AddresseeLineEdit::s_LDAPTimer = 0L;
70 TQString* AddresseeLineEdit::s_LDAPText = 0L;
71 AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
75 TQMap<TQString,int>* s_completionSourceWeights = 0;
80 TQMap<int, int>* AddresseeLineEdit::s_ldapClientToCompletionSourceMap = 0;
82 static KStaticDeleter<KMailCompletion> completionDeleter;
83 static KStaticDeleter<KPIM::CompletionItemsMap> completionItemsDeleter;
84 static KStaticDeleter<TQTimer> ldapTimerDeleter;
85 static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
86 static KStaticDeleter<TQString> ldapTextDeleter;
87 static KStaticDeleter<TQStringList> completionSourcesDeleter;
88 static KStaticDeleter<TQMap<TQString,int> > completionSourceWeightsDeleter;
89 static KStaticDeleter<TQMap<int, int> > ldapClientToCompletionSourceMapDeleter;
92 static TQCString newLineEditDCOPObjectName()
94 static int s_count = 0;
95 TQCString name(
"KPIM::AddresseeLineEdit" );
98 name += TQCString().setNum( s_count );
103 static const TQString s_completionItemIndentString =
" ";
105 static bool itemIsHeader(
const TQListBoxItem* item )
107 return item && !item->text().startsWith( s_completionItemIndentString );
112 AddresseeLineEdit::AddresseeLineEdit( TQWidget* parent,
bool useCompletion,
114 :
ClickLineEdit( parent, TQString(), name ), DCOPObject( newLineEditDCOPObjectName() ),
115 m_useSemiColonAsSeparator( false ), m_allowDistLists( true )
117 m_useCompletion = useCompletion;
118 m_completionInitialized =
false;
119 m_smartPaste =
false;
120 m_addressBookConnected =
false;
121 m_searchExtended =
false;
125 if ( m_useCompletion )
126 s_addressesDirty =
true;
129 void AddresseeLineEdit::updateLDAPWeights()
133 s_LDAPSearch->updateCompletionWeights();
134 TQValueList< LdapClient* > clients = s_LDAPSearch->clients();
136 for ( TQValueList<LdapClient*>::iterator it = clients.begin(); it != clients.end(); ++it, ++clientIndex ) {
137 const int sourceIndex = addCompletionSource(
"LDAP server: " + (*it)->server().host(), (*it)->completionWeight() );
138 s_ldapClientToCompletionSourceMap->insert( clientIndex, sourceIndex );
142 void AddresseeLineEdit::init()
144 if ( !s_completion ) {
146 s_completion->setOrder( completionOrder() );
147 s_completion->setIgnoreCase(
true );
149 completionItemsDeleter.setObject( s_completionItemMap,
new KPIM::CompletionItemsMap() );
150 completionSourcesDeleter.setObject( s_completionSources,
new TQStringList() );
151 completionSourceWeightsDeleter.setObject( s_completionSourceWeights,
new TQMap<TQString,int> );
152 ldapClientToCompletionSourceMapDeleter.setObject( s_ldapClientToCompletionSourceMap,
new TQMap<int,int> );
157 if ( m_useCompletion ) {
158 if ( !s_LDAPTimer ) {
159 ldapTimerDeleter.setObject( s_LDAPTimer,
new TQTimer( 0,
"ldapTimerDeleter" ) );
161 ldapTextDeleter.setObject( s_LDAPText,
new TQString );
166 if ( !m_completionInitialized ) {
167 setCompletionObject( s_completion,
false );
168 connect(
this, TQ_SIGNAL( completion(
const TQString& ) ),
169 this, TQ_SLOT( slotCompletion() ) );
170 connect(
this, TQ_SIGNAL( returnPressed(
const TQString& ) ),
171 this, TQ_SLOT( slotReturnPressed(
const TQString& ) ) );
173 TDECompletionBox *box = completionBox();
174 connect( box, TQ_SIGNAL( highlighted(
const TQString& ) ),
175 this, TQ_SLOT( slotPopupCompletion(
const TQString& ) ) );
176 connect( box, TQ_SIGNAL( userCancelled(
const TQString& ) ),
177 TQ_SLOT( slotUserCancelled(
const TQString& ) ) );
180 if ( !connectDCOPSignal( 0,
"KPIM::IMAPCompletionOrder",
"orderChanged()",
181 "slotIMAPCompletionOrderChanged()",
false ) )
182 kdError() <<
"AddresseeLineEdit: connection to orderChanged() failed" << endl;
184 connect( s_LDAPTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotStartLDAPLookup() ) );
185 connect( s_LDAPSearch, TQ_SIGNAL( searchData(
const KPIM::LdapResultList& ) ),
186 TQ_SLOT( slotLDAPSearchData(
const KPIM::LdapResultList& ) ) );
188 m_completionInitialized =
true;
193 AddresseeLineEdit::~AddresseeLineEdit()
195 if ( s_LDAPSearch && s_LDAPLineEdit ==
this )
199 void AddresseeLineEdit::setFont(
const TQFont& font )
201 KLineEdit::setFont( font );
202 if ( m_useCompletion )
203 completionBox()->setFont( font );
206 void AddresseeLineEdit::allowSemiColonAsSeparator(
bool useSemiColonAsSeparator )
208 m_useSemiColonAsSeparator = useSemiColonAsSeparator;
211 void AddresseeLineEdit::allowDistributionLists(
bool allowDistLists )
213 m_allowDistLists = allowDistLists;
216 void AddresseeLineEdit::keyPressEvent( TQKeyEvent *e )
220 if ( TDEStdAccel::shortcut( TDEStdAccel::SubstringCompletion ).contains( KKey( e ) ) ) {
222 updateSearchString();
223 doCompletion(
true );
225 }
else if ( TDEStdAccel::shortcut( TDEStdAccel::TextCompletion ).contains( KKey( e ) ) ) {
226 int len = text().length();
228 if ( len == cursorPosition() ) {
229 updateSearchString();
230 doCompletion(
true );
235 const TQString oldContent = text();
237 KLineEdit::keyPressEvent( e );
241 if ( oldContent == text() )
244 if ( e->isAccepted() ) {
245 updateSearchString();
246 TQString searchString( m_searchString );
248 if ( m_searchExtended )
249 searchString = m_searchString.mid( 1 );
251 if ( m_useCompletion && s_LDAPTimer != NULL ) {
252 if ( *s_LDAPText != searchString || s_LDAPLineEdit !=
this )
255 *s_LDAPText = searchString;
256 s_LDAPLineEdit =
this;
257 s_LDAPTimer->start( 500,
true );
262 void AddresseeLineEdit::insert(
const TQString &t )
264 if ( !m_smartPaste ) {
265 KLineEdit::insert( t );
271 TQString newText = t.stripWhiteSpace();
272 if ( newText.isEmpty() )
276 TQStringList lines = TQStringList::split( TQRegExp(
"\r?\n"), newText,
false );
277 for ( TQStringList::iterator it = lines.begin();
278 it != lines.end(); ++it ) {
280 (*it).remove( TQRegExp(
",?\\s*$") );
282 newText = lines.join(
", " );
284 if ( newText.startsWith(
"mailto:") ) {
286 newText = url.path();
288 else if ( newText.find(
" at ") != -1 ) {
290 newText.replace(
" at ",
"@" );
291 newText.replace(
" dot ",
"." );
293 else if ( newText.find(
"(at)") != -1 ) {
294 newText.replace( TQRegExp(
"\\s*\\(at\\)\\s*"),
"@" );
297 TQString contents = text();
299 int pos = cursorPosition( );
301 if ( hasSelectedText() ) {
303 start_sel = selectionStart();
305 contents = contents.left( start_sel ) + contents.mid( start_sel + selectedText().length() );
308 int eot = contents.length();
309 while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() ) {
313 contents = TQString();
314 }
else if ( pos >= eot ) {
315 if ( contents[ eot - 1 ] ==
',' ) {
318 contents.truncate( eot );
323 contents = contents.left( pos ) + newText + contents.mid( pos );
326 setCursorPosition( pos + newText.length() );
329 void AddresseeLineEdit::setText(
const TQString & text )
331 ClickLineEdit::setText( text.stripWhiteSpace() );
334 void AddresseeLineEdit::paste()
336 if ( m_useCompletion )
340 m_smartPaste =
false;
343 void AddresseeLineEdit::mouseReleaseEvent( TQMouseEvent *e )
347 && TQApplication::clipboard()->supportsSelection()
349 && e->button() == TQt::MidButton ) {
353 KLineEdit::mouseReleaseEvent( e );
354 m_smartPaste =
false;
357 void AddresseeLineEdit::dropEvent( TQDropEvent *e )
360 if ( !isReadOnly() ) {
361 if ( KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
362 TQString contents = text();
364 int eot = contents.length();
365 while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
368 contents = TQString();
369 else if ( contents[ eot - 1 ] ==
',' ) {
371 contents.truncate( eot );
373 bool mailtoURL =
false;
375 for ( KURL::List::Iterator it = uriList.begin();
376 it != uriList.end(); ++it ) {
377 if ( !contents.isEmpty() )
378 contents.append(
", " );
380 if ( u.protocol() ==
"mailto" ) {
382 contents.append( (*it).path() );
392 TQString dropData = TQString::fromUtf8( e->encodedData(
"text/plain" ) );
393 TQStringList addrs = splitEmailAddrList( dropData );
394 if ( addrs.count() > 0 ) {
395 setText( normalizeAddressesAndDecodeIDNs( dropData ) );
402 if ( m_useCompletion )
404 TQLineEdit::dropEvent( e );
405 m_smartPaste =
false;
408 void AddresseeLineEdit::cursorAtEnd()
410 setCursorPosition( text().length() );
413 void AddresseeLineEdit::enableCompletion(
bool enable )
415 m_useCompletion = enable;
418 void AddresseeLineEdit::doCompletion(
bool ctrlT )
420 m_lastSearchMode = ctrlT;
422 TDEGlobalSettings::Completion mode = completionMode();
424 if ( mode == TDEGlobalSettings::CompletionNone )
427 if ( s_addressesDirty ) {
429 s_completion->setOrder( completionOrder() );
434 const TQStringList completions = getAdjustedCompletionItems(
false );
436 if ( completions.count() > 1 )
438 else if ( completions.count() == 1 )
439 setText( m_previousAddresses + completions.first().stripWhiteSpace() );
441 setCompletedItems( completions,
true );
444 setCompletionMode( mode );
450 case TDEGlobalSettings::CompletionPopupAuto:
452 if ( m_searchString.isEmpty() )
456 case TDEGlobalSettings::CompletionPopup:
458 const TQStringList items = getAdjustedCompletionItems(
true );
459 setCompletedItems( items,
false );
463 case TDEGlobalSettings::CompletionShell:
465 TQString match = s_completion->makeCompletion( m_searchString );
466 if ( !match.isNull() && match != m_searchString ) {
467 setText( m_previousAddresses + match );
474 case TDEGlobalSettings::CompletionMan:
475 case TDEGlobalSettings::CompletionAuto:
478 setCompletionMode( completionMode() );
480 if ( !m_searchString.isEmpty() ) {
483 if ( m_searchExtended && m_searchString ==
"\"" ){
484 m_searchExtended =
false;
485 m_searchString = TQString();
486 setText( m_previousAddresses );
490 TQString match = s_completion->makeCompletion( m_searchString );
492 if ( !match.isEmpty() ) {
493 if ( match != m_searchString ) {
494 TQString adds = m_previousAddresses + match;
495 setCompletedText( adds );
498 if ( !m_searchString.startsWith(
"\"" ) ) {
500 match = s_completion->makeCompletion(
"\"" + m_searchString );
501 if ( !match.isEmpty() && match != m_searchString ) {
502 m_searchString =
"\"" + m_searchString;
503 m_searchExtended =
true;
504 setText( m_previousAddresses + m_searchString );
505 setCompletedText( m_previousAddresses + match );
507 }
else if ( m_searchExtended ) {
509 m_searchString = m_searchString.mid( 1 );
510 m_searchExtended =
false;
511 setText( m_previousAddresses + m_searchString );
513 match = s_completion->makeCompletion( m_searchString );
514 if ( !match.isEmpty() && match != m_searchString ) {
515 TQString adds = m_previousAddresses + match;
516 setCompletedText( adds );
524 case TDEGlobalSettings::CompletionNone:
530 void AddresseeLineEdit::slotPopupCompletion(
const TQString& completion )
532 setText( m_previousAddresses + completion.stripWhiteSpace() );
535 updateSearchString();
538 void AddresseeLineEdit::slotReturnPressed(
const TQString& item )
541 TQListBoxItem* i = completionBox()->selectedItem();
543 slotPopupCompletion( i->text() );
546 void AddresseeLineEdit::loadContacts()
548 s_completion->clear();
549 s_completionItemMap->clear();
550 s_addressesDirty =
false;
553 TQApplication::setOverrideCursor( KCursor::waitCursor() );
555 TDEConfig config(
"kpimcompletionorder" );
556 config.setGroup(
"CompletionWeights" );
558 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self(
true );
561 TQPtrList<TDEABC::Resource> resources( addressBook->resources() );
562 for( TQPtrListIterator<TDEABC::Resource> resit( resources ); *resit; ++resit ) {
563 TDEABC::Resource* resource = *resit;
566 const TQMap<TQString, TQString> uidToResourceMap = resabc->
uidToResourceMap();
567 TDEABC::Resource::Iterator it;
568 for ( it = resource->begin(); it != resource->end(); ++it ) {
569 TQString uid = (*it).uid();
570 TQMap<TQString, TQString>::const_iterator wit = uidToResourceMap.find( uid );
573 const int idx = addCompletionSource( subresourceLabel, weight );
576 addContact( *it, weight, idx );
579 int weight = config.readNumEntry( resource->identifier(), 60 );
580 int sourceIndex = addCompletionSource( resource->resourceName(), weight );
581 TDEABC::Resource::Iterator it;
582 for ( it = resource->begin(); it != resource->end(); ++it ) {
583 addContact( *it, weight, sourceIndex );
588 #ifndef TDEPIM_NEW_DISTRLISTS
589 int weight = config.readNumEntry(
"DistributionLists", 60 );
590 TDEABC::DistributionListManager manager( addressBook );
592 const TQStringList distLists = manager.listNames();
593 TQStringList::const_iterator listIt;
594 int idx = addCompletionSource( i18n(
"Distribution Lists" ) );
595 for ( listIt = distLists.begin(); listIt != distLists.end(); ++listIt ) {
598 addCompletionItem( (*listIt).simplifyWhiteSpace(), weight, idx );
601 TQStringList sl( (*listIt).simplifyWhiteSpace() );
602 addCompletionItem( (*listIt).simplifyWhiteSpace(), weight, idx, &sl );
607 TQApplication::restoreOverrideCursor();
609 if ( !m_addressBookConnected ) {
610 connect( addressBook, TQ_SIGNAL( addressBookChanged( AddressBook* ) ), TQ_SLOT( loadContacts() ) );
611 m_addressBookConnected =
true;
615 void AddresseeLineEdit::addContact(
const TDEABC::Addressee& addr,
int weight,
int source )
617 #ifdef TDEPIM_NEW_DISTRLISTS
618 if ( KPIM::DistributionList::isDistributionList( addr ) ) {
621 if ( m_allowDistLists ) {
623 addCompletionItem( addr.formattedName(), weight, source );
626 TQStringList sl( addr.formattedName() );
627 addCompletionItem( addr.formattedName(), weight, source, &sl );
634 const TQStringList emails = addr.emails();
635 TQStringList::ConstIterator it;
636 const int prefEmailWeight = 1;
637 int isPrefEmail = prefEmailWeight;
638 for ( it = emails.begin(); it != emails.end(); ++it ) {
640 const TQString email( (*it) );
641 const TQString givenName = addr.givenName();
642 const TQString familyName= addr.familyName();
643 const TQString nickName = addr.nickName();
644 const TQString domain = email.mid( email.find(
'@' ) + 1 );
645 TQString fullEmail = addr.fullEmail( email );
649 if ( givenName.isEmpty() && familyName.isEmpty() ) {
650 addCompletionItem( fullEmail, weight + isPrefEmail, source );
652 const TQString byFirstName=
"\"" + givenName +
" " + familyName +
"\" <" + email +
">";
653 const TQString byLastName =
"\"" + familyName +
", " + givenName +
"\" <" + email +
">";
654 addCompletionItem( byFirstName, weight + isPrefEmail, source );
655 addCompletionItem( byLastName, weight + isPrefEmail, source );
658 addCompletionItem( email, weight + isPrefEmail, source );
660 if ( !nickName.isEmpty() ){
661 const TQString byNick =
"\"" + nickName +
"\" <" + email +
">";
662 addCompletionItem( byNick, weight + isPrefEmail, source );
665 if ( !domain.isEmpty() ){
666 const TQString byDomain =
"\"" + domain +
" " + familyName +
" " + givenName +
"\" <" + email +
">";
667 addCompletionItem( byDomain, weight + isPrefEmail, source );
671 TQStringList keyWords;
672 const TQString realName = addr.realName();
674 if ( !givenName.isEmpty() && !familyName.isEmpty() ) {
675 keyWords.append( givenName +
" " + familyName );
676 keyWords.append( familyName +
" " + givenName );
677 keyWords.append( familyName +
", " + givenName);
678 }
else if ( !givenName.isEmpty() )
679 keyWords.append( givenName );
680 else if ( !familyName.isEmpty() )
681 keyWords.append( familyName );
683 if ( !nickName.isEmpty() )
684 keyWords.append( nickName );
686 if ( !realName.isEmpty() )
687 keyWords.append( realName );
689 if ( !domain.isEmpty() )
690 keyWords.append( domain );
692 keyWords.append( email );
700 if ( isPrefEmail == prefEmailWeight )
701 fullEmail.replace(
" <",
" <" );
703 addCompletionItem( fullEmail, weight + isPrefEmail, source, &keyWords );
707 int len = (*it).length();
708 if ( len == 0 )
continue;
709 if(
'\0' == (*it)[len-1] )
711 const TQString tmp = (*it).left( len );
712 const TQString fullEmail = addr.fullEmail( tmp );
714 addCompletionItem( fullEmail.simplifyWhiteSpace(), weight, source );
718 TQString name( addr.realName().simplifyWhiteSpace() );
719 if( name.endsWith(
"\"") )
720 name.truncate( name.length()-1 );
721 if( name.startsWith(
"\"") )
722 name = name.mid( 1 );
725 if ( !name.isEmpty() )
726 addCompletionItem( addr.preferredEmail() +
" (" + name +
")", weight, source );
730 while( ( i = name.findRev(
' ') ) > 1 && !bDone ) {
731 TQString sLastName( name.mid( i+1 ) );
732 if( ! sLastName.isEmpty() &&
733 2 <= sLastName.length() &&
734 ! sLastName.endsWith(
".") ) {
736 if( !name.isEmpty() ){
737 sLastName.prepend(
"\"" );
738 sLastName.append(
", " + name +
"\" <" );
740 TQString sExtraEntry( sLastName );
741 sExtraEntry.append( tmp.isEmpty() ? addr.preferredEmail() : tmp );
742 sExtraEntry.append(
">" );
744 addCompletionItem( sExtraEntry.simplifyWhiteSpace(), weight, source );
749 if( name.endsWith(
"\"") )
750 name.truncate( name.length()-1 );
757 void AddresseeLineEdit::addCompletionItem(
const TQString&
string,
int weight,
int completionItemSource,
const TQStringList * keyWords )
761 CompletionItemsMap::iterator it = s_completionItemMap->find(
string );
762 if ( it != s_completionItemMap->end() ) {
763 weight = TQMAX( ( *it ).first, weight );
764 ( *it ).first = weight;
766 s_completionItemMap->insert(
string, qMakePair( weight, completionItemSource ) );
769 s_completion->addItem(
string, weight );
771 s_completion->addItemWithKeys(
string, weight, keyWords );
774 void AddresseeLineEdit::slotStartLDAPLookup()
776 TDEGlobalSettings::Completion mode = completionMode();
778 if ( mode == TDEGlobalSettings::CompletionNone )
781 if ( !s_LDAPSearch->isAvailable() ) {
784 if ( s_LDAPLineEdit !=
this )
787 startLoadingLDAPEntries();
790 void AddresseeLineEdit::stopLDAPLookup()
792 s_LDAPSearch->cancelSearch();
793 s_LDAPLineEdit = NULL;
796 void AddresseeLineEdit::startLoadingLDAPEntries()
798 TQString s( *s_LDAPText );
801 int n = s.findRev(
',' );
803 prevAddr = s.left( n + 1 ) +
' ';
804 s = s.mid( n + 1, 255 ).stripWhiteSpace();
811 s_LDAPSearch->startSearch( s );
814 void AddresseeLineEdit::slotLDAPSearchData(
const KPIM::LdapResultList& adrs )
816 if ( adrs.isEmpty() || s_LDAPLineEdit !=
this )
819 for ( KPIM::LdapResultList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
820 TDEABC::Addressee addr;
821 addr.setNameFromString( (*it).name );
822 addr.setEmails( (*it).email );
824 if ( !s_ldapClientToCompletionSourceMap->contains( (*it).clientNumber ) )
827 addContact( addr, (*it).completionWeight, (*s_ldapClientToCompletionSourceMap)[ (*it ).clientNumber ] );
830 if ( (hasFocus() || completionBox()->hasFocus() )
831 && completionMode() != TDEGlobalSettings::CompletionNone
832 && completionMode() != TDEGlobalSettings::CompletionShell ) {
833 setText( m_previousAddresses + m_searchString );
836 if ( m_searchString.stripWhiteSpace() != completionBox()->currentText().stripWhiteSpace() )
837 doCompletion( m_lastSearchMode );
841 void AddresseeLineEdit::setCompletedItems(
const TQStringList& items,
bool autoSuggest )
843 TDECompletionBox* completionBox = this->completionBox();
845 if ( !items.isEmpty() &&
846 !(items.count() == 1 && m_searchString == items.first()) )
848 TQString oldCurrentText = completionBox->currentText();
849 TQListBoxItem *itemUnderMouse = completionBox->itemAt(
850 completionBox->viewport()->mapFromGlobal(TQCursor::pos()) );
851 TQString oldTextUnderMouse;
852 TQPoint oldPosOfItemUnderMouse;
853 if ( itemUnderMouse ) {
854 oldTextUnderMouse = itemUnderMouse->text();
855 oldPosOfItemUnderMouse = completionBox->itemRect( itemUnderMouse ).topLeft();
858 completionBox->setItems( items );
860 if ( !completionBox->isVisible() ) {
861 if ( !m_searchString.isEmpty() )
862 completionBox->setCancelledText( m_searchString );
863 completionBox->popup();
867 if ( s_completion->order() == TDECompletion::Weighted )
868 tqApp->installEventFilter(
this );
873 TQListBoxItem* item = 0;
874 if ( oldCurrentText.isEmpty()
875 || ( item = completionBox->findItem( oldCurrentText ) ) == 0 ) {
876 item = completionBox->item( 1 );
880 if ( itemUnderMouse ) {
881 TQListBoxItem *newItemUnderMouse = completionBox->findItem( oldTextUnderMouse );
884 if ( newItemUnderMouse ) {
885 TQRect r = completionBox->itemRect( newItemUnderMouse );
886 TQPoint target = r.topLeft();
887 if ( oldPosOfItemUnderMouse != target ) {
888 target.setX( target.x() + r.width()/2 );
889 TQCursor::setPos( completionBox->viewport()->mapToGlobal(target) );
893 completionBox->blockSignals(
true );
894 completionBox->setSelected( item,
true );
895 completionBox->setCurrentItem( item );
896 completionBox->ensureCurrentVisible();
898 completionBox->blockSignals(
false );
903 int index = items.first().find( m_searchString );
904 TQString newText = items.first().mid( index );
905 setUserSelection(
false);
906 setCompletedText(newText,
true);
911 if ( completionBox && completionBox->isVisible() ) {
912 completionBox->hide();
913 completionBox->setItems( TQStringList() );
918 TQPopupMenu* AddresseeLineEdit::createPopupMenu()
920 TQPopupMenu *menu = KLineEdit::createPopupMenu();
924 if ( m_useCompletion ){
925 menu->setItemVisible( ShortAutoCompletion,
false );
926 menu->setItemVisible( PopupAutoCompletion,
false );
927 menu->insertItem( i18n(
"Configure Completion Order..." ),
928 this, TQ_SLOT( slotEditCompletionOrder() ) );
933 void AddresseeLineEdit::slotEditCompletionOrder()
936 CompletionOrderEditor editor( s_LDAPSearch,
this );
938 if ( m_useCompletion ) {
940 s_addressesDirty =
true;
944 void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
946 if ( m_useCompletion )
947 s_addressesDirty =
true;
950 void KPIM::AddresseeLineEdit::slotUserCancelled(
const TQString& cancelText )
952 if ( s_LDAPSearch && s_LDAPLineEdit ==
this )
954 userCancelled( m_previousAddresses + cancelText );
957 void AddresseeLineEdit::updateSearchString()
959 m_searchString = text();
962 bool inQuote =
false;
963 uint searchStringLength = m_searchString.length();
964 for ( uint i = 0; i < searchStringLength; ++i ) {
965 if ( m_searchString[ i ] ==
'"' ) {
968 if ( m_searchString[ i ] ==
'\\' &&
969 (i + 1) < searchStringLength && m_searchString[ i + 1 ] ==
'"' ) {
975 if ( i < searchStringLength &&
976 ( m_searchString[ i ] ==
',' ||
977 ( m_useSemiColonAsSeparator && m_searchString[ i ] ==
';' ) ) ) {
985 int len = m_searchString.length();
988 while ( n < len && m_searchString[ n ].isSpace() )
991 m_previousAddresses = m_searchString.left( n );
992 m_searchString = m_searchString.mid( n ).stripWhiteSpace();
994 m_previousAddresses = TQString();
998 void KPIM::AddresseeLineEdit::slotCompletion()
1002 updateSearchString();
1003 if ( completionBox() )
1004 completionBox()->setCancelledText( m_searchString );
1005 doCompletion(
false );
1009 TDECompletion::CompOrder KPIM::AddresseeLineEdit::completionOrder()
1011 TDEConfig config(
"kpimcompletionorder" );
1012 config.setGroup(
"General" );
1013 const TQString order = config.readEntry(
"CompletionOrder",
"Weighted" );
1015 if ( order ==
"Weighted" )
1016 return TDECompletion::Weighted;
1018 return TDECompletion::Sorted;
1021 int KPIM::AddresseeLineEdit::addCompletionSource(
const TQString &source,
int weight )
1023 TQMap<TQString,int>::iterator it = s_completionSourceWeights->find( source );
1024 if ( it == s_completionSourceWeights->end() )
1025 s_completionSourceWeights->insert( source, weight );
1027 (*s_completionSourceWeights)[source] = weight;
1029 int sourceIndex = s_completionSources->findIndex( source );
1030 if ( sourceIndex == -1 ) {
1031 s_completionSources->append( source );
1032 return s_completionSources->size() - 1;
1038 bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
1040 if ( obj == completionBox() ) {
1041 if ( e->type() == TQEvent::MouseButtonPress ||
1042 e->type() == TQEvent::MouseMove ||
1043 e->type() == TQEvent::MouseButtonRelease ||
1044 e->type() == TQEvent::MouseButtonDblClick ) {
1045 TQMouseEvent* me =
static_cast<TQMouseEvent*
>( e );
1047 TQListBoxItem *item = completionBox()->itemAt( me->pos() );
1051 bool eat = e->type() == TQEvent::MouseMove;
1056 if ( e->type() == TQEvent::MouseButtonPress
1057 || me->state() & TQt::LeftButton || me->state() & TQt::MidButton
1058 || me->state() & TQt::RightButton ) {
1059 if ( itemIsHeader(item) ) {
1065 completionBox()->setCurrentItem( item );
1066 completionBox()->setSelected( completionBox()->index( item ),
true );
1067 if ( e->type() == TQEvent::MouseMove )
1073 if ( ( obj ==
this ) &&
1074 ( e->type() == TQEvent::AccelOverride ) ) {
1075 TQKeyEvent *ke =
static_cast<TQKeyEvent*
>( e );
1076 if ( ke->key() == Key_Up || ke->key() == Key_Down || ke->key() == Key_Tab ) {
1081 if ( ( obj ==
this ) &&
1082 ( e->type() == TQEvent::KeyPress || e->type() == TQEvent::KeyRelease ) &&
1083 completionBox()->isVisible() ) {
1084 TQKeyEvent *ke =
static_cast<TQKeyEvent*
>( e );
1085 int currentIndex = completionBox()->currentItem();
1086 if ( currentIndex < 0 ) {
1090 if ( ke->key() == Key_Up ) {
1094 TQListBoxItem *itemAbove = completionBox()->item( currentIndex );
1095 if ( itemAbove && itemIsHeader(itemAbove) ) {
1098 if ( currentIndex > 0 && completionBox()->item( currentIndex - 1 ) ) {
1100 completionBox()->setCurrentItem( itemAbove->prev() );
1101 completionBox()->setSelected( currentIndex - 1,
true );
1102 }
else if ( currentIndex == 0 ) {
1105 completionBox()->ensureVisible( 0, 0 );
1107 if ( itemIsHeader( completionBox()->item( currentIndex ) ) ) {
1110 completionBox()->setCurrentItem( itemAbove );
1111 completionBox()->setSelected( currentIndex,
true );
1115 }
else if ( ke->key() == Key_Down ) {
1118 TQListBoxItem *itemBelow = completionBox()->item( currentIndex );
1119 if ( itemBelow && itemIsHeader( itemBelow ) ) {
1120 if ( completionBox()->item( currentIndex + 1 ) ) {
1122 completionBox()->setCurrentItem( itemBelow->next() );
1123 completionBox()->setSelected( currentIndex + 1,
true );
1126 completionBox()->setCurrentItem( itemBelow );
1127 completionBox()->setSelected( currentIndex,
true );
1132 if ( !itemBelow && currentIndex == 1 ) {
1133 completionBox()->setSelected( currentIndex,
true );
1138 TQListBoxItem *item = completionBox()->item( currentIndex );
1139 if ( item && itemIsHeader(item) ) {
1140 completionBox()->setSelected( currentIndex,
true );
1142 }
else if ( e->type() == TQEvent::KeyRelease &&
1143 ( ke->key() == Key_Tab || ke->key() == Key_Backtab ) ) {
1146 TQListBoxItem *myHeader = 0;
1147 const int iterationstep = ke->key() == Key_Tab ? 1 : -1;
1148 int i = TQMIN( TQMAX( currentIndex - iterationstep, 0 ), completionBox()->count() - 1 );
1150 if ( itemIsHeader( completionBox()->item(i) ) ) {
1151 myHeader = completionBox()->item( i );
1156 Q_ASSERT( myHeader );
1159 TQListBoxItem *nextHeader = 0;
1163 if ( ke->key() == Key_Tab ) {
1166 i = completionBox()->index( myHeader );
1168 j = completionBox()->count() - 1;
1170 j = ( i - 1 ) % completionBox()->count();
1173 while ( ( nextHeader = completionBox()->item( j ) ) && nextHeader != myHeader ) {
1174 if ( itemIsHeader(nextHeader) ) {
1177 j = (j + iterationstep) % completionBox()->count();
1179 if ( nextHeader && nextHeader != myHeader ) {
1180 TQListBoxItem *item = completionBox()->item( j + 1 );
1181 if ( item && !itemIsHeader(item) ) {
1182 completionBox()->setSelected( item,
true );
1183 completionBox()->setCurrentItem( item );
1184 completionBox()->ensureCurrentVisible();
1190 return ClickLineEdit::eventFilter( obj, e );
1193 class SourceWithWeight {
1196 TQString sourceName;
1199 bool operator< (
const SourceWithWeight &other ) {
1200 if ( weight > other.weight )
1202 if ( weight < other.weight )
1204 return sourceName < other.sourceName;
1208 const TQStringList KPIM::AddresseeLineEdit::getAdjustedCompletionItems(
bool fullSearch )
1210 TQStringList items = fullSearch ?
1211 s_completion->allMatches( m_searchString )
1212 : s_completion->substringCompletion( m_searchString );
1223 int lastSourceIndex = -1;
1228 TQMap<int, TQStringList> sections;
1229 TQStringList sortedItems;
1230 for ( TQStringList::Iterator it = items.begin(); it != items.end(); ++it, ++i ) {
1231 CompletionItemsMap::const_iterator cit = s_completionItemMap->find(*it);
1232 if ( cit == s_completionItemMap->end() )
1234 int idx = (*cit).second;
1236 if ( s_completion->order() == TDECompletion::Weighted ) {
1237 if ( lastSourceIndex == -1 || lastSourceIndex != idx ) {
1238 const TQString sourceLabel( (*s_completionSources)[idx] );
1239 if ( sections.find(idx) == sections.end() ) {
1240 items.insert( it, sourceLabel );
1242 lastSourceIndex = idx;
1244 (*it) = (*it).prepend( s_completionItemIndentString );
1246 (*it).replace(
" <",
" <" );
1248 sections[idx].append( *it );
1250 if ( s_completion->order() == TDECompletion::Sorted ) {
1251 sortedItems.append( *it );
1255 if ( s_completion->order() == TDECompletion::Weighted ) {
1258 TQValueList<SourceWithWeight> sourcesAndWeights;
1259 for ( uint i = 0; i < s_completionSources->size(); i++ ) {
1260 SourceWithWeight sww;
1261 sww.sourceName = (*s_completionSources)[i];
1262 sww.weight = (*s_completionSourceWeights)[sww.sourceName];
1264 sourcesAndWeights.append( sww );
1266 qHeapSort( sourcesAndWeights );
1269 for( uint i = 0; i < sourcesAndWeights.size(); i++ ) {
1270 TQStringList sectionItems = sections[sourcesAndWeights[i].index];
1271 if ( !sectionItems.isEmpty() ) {
1272 sortedItems.append( sourcesAndWeights[i].sourceName );
1273 TQStringList sectionItems = sections[sourcesAndWeights[i].index];
1274 for ( TQStringList::Iterator sit( sectionItems.begin() ), send( sectionItems.end() );
1275 sit != send; ++sit ) {
1276 sortedItems.append( *sit );
1285 #include "addresseelineedit.moc"
This class provides a KLineEdit which contains a greyed-out hinting text as long as the user didn't e...
KMailCompletion allows lookup of email addresses by keyword.
This class is the implementation of subfolder resources for KABC.
virtual TQString subresourceLabel(const TQString &) const =0
Label for a given subresource.
virtual int subresourceCompletionWeight(const TQString &) const =0
Completion weight for a given subresource.
virtual TQMap< TQString, TQString > uidToResourceMap() const =0
Get the UID to subresource map.
TDEPIM classes for drag and drop of mails.