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 <tdestandarddirs.h>
48#include <kstaticdeleter.h>
49#include <tdestdaccel.h>
53#include <tqpopupmenu.h>
54#include <tqapplication.h>
59#include <tqdragobject.h>
60#include <tqclipboard.h>
65KPIM::CompletionItemsMap* AddresseeLineEdit::s_completionItemMap = 0L;
66TQStringList* AddresseeLineEdit::s_completionSources = 0L;
67bool AddresseeLineEdit::s_addressesDirty =
false;
68TQTimer* AddresseeLineEdit::s_LDAPTimer = 0L;
70TQString* AddresseeLineEdit::s_LDAPText = 0L;
71AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
75TQMap<TQString,int>* s_completionSourceWeights = 0;
80TQMap<int, int>* AddresseeLineEdit::s_ldapClientToCompletionSourceMap = 0;
82static KStaticDeleter<KMailCompletion> completionDeleter;
83static KStaticDeleter<KPIM::CompletionItemsMap> completionItemsDeleter;
84static KStaticDeleter<TQTimer> ldapTimerDeleter;
85static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
86static KStaticDeleter<TQString> ldapTextDeleter;
87static KStaticDeleter<TQStringList> completionSourcesDeleter;
88static KStaticDeleter<TQMap<TQString,int> > completionSourceWeightsDeleter;
89static KStaticDeleter<TQMap<int, int> > ldapClientToCompletionSourceMapDeleter;
92static TQCString newLineEditDCOPObjectName()
94 static int s_count = 0;
95 TQCString name(
"KPIM::AddresseeLineEdit" );
98 name += TQCString().setNum( s_count );
103static const TQString s_completionItemIndentString =
" ";
105static bool itemIsHeader(
const TQListBoxItem* item )
107 return item && !item->text().startsWith( s_completionItemIndentString );
112AddresseeLineEdit::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;
129void 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 );
142void 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;
193AddresseeLineEdit::~AddresseeLineEdit()
195 if ( s_LDAPSearch && s_LDAPLineEdit ==
this )
199void AddresseeLineEdit::setFont(
const TQFont& font )
201 KLineEdit::setFont( font );
202 if ( m_useCompletion )
203 completionBox()->setFont( font );
206void AddresseeLineEdit::allowSemiColonAsSeparator(
bool useSemiColonAsSeparator )
208 m_useSemiColonAsSeparator = useSemiColonAsSeparator;
211void AddresseeLineEdit::allowDistributionLists(
bool allowDistLists )
213 m_allowDistLists = allowDistLists;
216void 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 );
262void 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() );
329void AddresseeLineEdit::setText(
const TQString & text )
331 ClickLineEdit::setText( text.stripWhiteSpace() );
334void AddresseeLineEdit::paste()
336 if ( m_useCompletion )
340 m_smartPaste =
false;
343void AddresseeLineEdit::mouseReleaseEvent( TQMouseEvent *e )
347 && TQApplication::clipboard()->supportsSelection()
349 && e->button() == TQt::MidButton ) {
353 KLineEdit::mouseReleaseEvent( e );
354 m_smartPaste =
false;
357void 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;
408void AddresseeLineEdit::cursorAtEnd()
410 setCursorPosition( text().length() );
413void AddresseeLineEdit::enableCompletion(
bool enable )
415 m_useCompletion = enable;
418void 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:
530void AddresseeLineEdit::slotPopupCompletion(
const TQString& completion )
532 setText( m_previousAddresses + completion.stripWhiteSpace() );
535 updateSearchString();
538void AddresseeLineEdit::slotReturnPressed(
const TQString& item )
541 TQListBoxItem* i = completionBox()->selectedItem();
543 slotPopupCompletion( i->text() );
546void 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;
615void 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 );
757void 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 );
774void AddresseeLineEdit::slotStartLDAPLookup()
776 TDEGlobalSettings::Completion mode = completionMode();
778 if ( mode == TDEGlobalSettings::CompletionNone )
781 if ( !s_LDAPSearch->isAvailable() ) {
784 if ( s_LDAPLineEdit !=
this )
787 startLoadingLDAPEntries();
790void AddresseeLineEdit::stopLDAPLookup()
792 s_LDAPSearch->cancelSearch();
793 s_LDAPLineEdit = NULL;
796void 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 );
814void 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 );
841void 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() );
918TQPopupMenu* 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() ) );
933void AddresseeLineEdit::slotEditCompletionOrder()
936 CompletionOrderEditor editor( s_LDAPSearch,
this );
938 if ( m_useCompletion ) {
940 s_addressesDirty =
true;
944void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
946 if ( m_useCompletion )
947 s_addressesDirty =
true;
950void KPIM::AddresseeLineEdit::slotUserCancelled(
const TQString& cancelText )
952 if ( s_LDAPSearch && s_LDAPLineEdit ==
this )
954 userCancelled( m_previousAddresses + cancelText );
957void 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();
998void KPIM::AddresseeLineEdit::slotCompletion()
1002 updateSearchString();
1003 if ( completionBox() )
1004 completionBox()->setCancelledText( m_searchString );
1005 doCompletion(
false );
1009TDECompletion::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;
1021int 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;
1038bool 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 );
1193class 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;
1208const 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 TQMap< TQString, TQString > uidToResourceMap() const =0
Get the UID to subresource map.
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.
TDEPIM classes for drag and drop of mails.