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.