addresslineedit.cpp Source File (kabc Library)

| # kabc Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# addresslineedit.cpp

    00001 /*
    00002     This file is part of libkabc.
    00003     Copyright (c) 2002 Helge Deller <deller@gmx.de>
    00004                   2002 Lubos Lunak <llunak@suse.cz>
    00005                   2001 Carsten Pfeiffer <pfeiffer@kde.org>
    00006                   2001 Waldo Bastian <bastian@kde.org>
    00007
    00008     This library is free software; you can redistribute it and/or
    00009     modify it under the terms of the GNU Library General Public
    00010     License as published by the Free Software Foundation; either
    00011     version 2 of the License, or (at your option) any later version.
    00012
    00013     This library is distributed in the hope that it will be useful,
    00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016     Library General Public License for more details.
    00017
    00018     You should have received a copy of the GNU Library General Public License
    00019     along with this library; see the file COPYING.LIB.  If not, write to
    00020     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021     Boston, MA 02111-1307, USA.
    00022 */
    00023
    00024 // $Id: addresslineedit.cpp,v 1.6.2.5 2003/07/22 06:28:05 deller Exp $
    00025
    00026 #include "addresslineedit.h"
    00027
    00028 #include <qobject.h>
    00029 #include <qptrlist.h>
    00030 #include <qregexp.h>
    00031 #include <qevent.h>
    00032 #include <qdragobject.h>
    00033
    00034 #include <kcompletionbox.h>
    00035 #include <kstdaccel.h>
    00036 #include <kurldrag.h>
    00037
    00038 #include <kabc/stdaddressbook.h>
    00039 #include <kabc/distributionlist.h>
    00040 #include <kurldrag.h>
    00041 #include "ldapclient.h"
    00042
    00043 #include <kdebug.h>
    00044
    00045 //=============================================================================
    00046 //
    00047 //   Class  AddressLineEdit
    00048 //
    00049 //=============================================================================
    00050
    00051
    00052 using namespace KABC;
    00053
    00054 KCompletion * AddressLineEdit::s_completion = 0L;
    00055 bool AddressLineEdit::s_addressesDirty = false;
    00056 QTimer* AddressLineEdit::s_LDAPTimer = 0L;
    00057 LdapSearch* AddressLineEdit::s_LDAPSearch = 0L;
    00058 QString* AddressLineEdit::s_LDAPText = 0L;
    00059 AddressLineEdit* AddressLineEdit::s_LDAPLineEdit = 0L;
    00060
    00061 AddressLineEdit::AddressLineEdit(QWidget* parent,
    00062                 bool useCompletion,
    00063                 const char *name)
    00064     : KLineEdit(parent,name)
    00065 {
    00066   m_useCompletion = useCompletion;
    00067   m_completionInitialized = false;
    00068   m_smartPaste = false;
    00069
    00070   init();
    00071
    00072   // Whenever a new AddressLineEdit is created (== a new composer is created),
    00073   // we set a dirty flag to reload the addresses upon the first completion.
    00074   // The address completions are shared between all AddressLineEdits.
    00075   // Is there a signal that tells us about addressbook updates?
    00076   if (m_useCompletion)
    00077     s_addressesDirty = true;
    00078 }
    00079
    00080
    00081 //-----------------------------------------------------------------------------
    00082 void AddressLineEdit::init()
    00083 {
    00084   if ( !s_completion ) {
    00085       s_completion = new KCompletion();
    00086       s_completion->setOrder( KCompletion::Sorted );
    00087       s_completion->setIgnoreCase( true );
    00088   }
    00089
    00090   if( m_useCompletion ) {
    00091       if( !s_LDAPTimer ) {
    00092         s_LDAPTimer = new QTimer;
    00093         s_LDAPSearch = new LdapSearch;
    00094         s_LDAPText = new QString;
    00095       }
    00096       connect( s_LDAPTimer, SIGNAL( timeout()), SLOT( slotStartLDAPLookup()));
    00097       connect( s_LDAPSearch, SIGNAL( searchData( const QStringList& )),
    00098         SLOT( slotLDAPSearchData( const QStringList& )));
    00099   }
    00100
    00101   if ( m_useCompletion && !m_completionInitialized )
    00102   {
    00103       setCompletionObject( s_completion, false ); // we handle it ourself
    00104       connect( this, SIGNAL( completion(const QString&)),
    00105                this, SLOT(slotCompletion() ));
    00106
    00107       KCompletionBox *box = completionBox();
    00108       connect( box, SIGNAL( highlighted( const QString& )),
    00109                this, SLOT( slotPopupCompletion( const QString& ) ));
    00110       connect( box, SIGNAL( userCancelled( const QString& )),
    00111                SLOT( slotSetTextAsEdited( const QString& )));
    00112
    00113       m_completionInitialized = true; // don't connect muliple times. That's
    00114                                       // ugly, tho, better have completionBox()
    00115                                       // virtual in KDE 4
    00116       // Why? This is only called once. Why should this be called more
    00117       // than once? And why was this protected?
    00118       // And while I'm at it: who deletes all those static objects? (pfeiffer)
    00119   }
    00120 }
    00121
    00122 //-----------------------------------------------------------------------------
    00123 AddressLineEdit::~AddressLineEdit()
    00124 {
    00125 }
    00126
    00127 //-----------------------------------------------------------------------------
    00128 void AddressLineEdit::setFont( const QFont& font )
    00129 {
    00130     KLineEdit::setFont( font );
    00131     if ( m_useCompletion )
    00132         completionBox()->setFont( font );
    00133 }
    00134
    00135 //-----------------------------------------------------------------------------
    00136 void AddressLineEdit::keyPressEvent(QKeyEvent *e)
    00137 {
    00138     bool accept = false;
    00139
    00140     if (KStdAccel::shortcut(KStdAccel::SubstringCompletion).contains(KKey(e)))
    00141     {
    00142       doCompletion(true);
    00143       accept = true;
    00144     }
    00145     else if (e->state()==ControlButton && e->key() == Key_Right)
    00146     {
    00147       if ((int)text().length() == cursorPosition()) // at End?
    00148       {
    00149         doCompletion(true);
    00150         accept = true;
    00151       }
    00152     }
    00153     else if (e->state()==ControlButton && e->key() == Key_V)
    00154     {
    00155       if (m_useCompletion)
    00156          m_smartPaste = true;
    00157       paste();
    00158       m_smartPaste = false;
    00159       accept = true;
    00160     }
    00161
    00162     if( !accept )
    00163         KLineEdit::keyPressEvent( e );
    00164
    00165     if( e->isAccepted())
    00166     {
    00167         if( m_useCompletion && s_LDAPTimer != NULL )
    00168         {
    00169             if( *s_LDAPText != text())
    00170                 stopLDAPLookup();
    00171             *s_LDAPText = text();
    00172             s_LDAPLineEdit = this;
    00173             s_LDAPTimer->start( 500, true );
    00174         }
    00175     }
    00176 }
    00177
    00178 void AddressLineEdit::mouseReleaseEvent( QMouseEvent * e )
    00179 {
    00180    if (m_useCompletion && (e->button() == MidButton))
    00181    {
    00182       m_smartPaste = true;
    00183       KLineEdit::mouseReleaseEvent(e);
    00184       m_smartPaste = false;
    00185       return;
    00186    }
    00187    KLineEdit::mouseReleaseEvent(e);
    00188 }
    00189
    00190 void AddressLineEdit::insert(const QString &t)
    00191 {
    00192     if (!m_smartPaste)
    00193     {
    00194        KLineEdit::insert(t);
    00195        return;
    00196     }
    00197     QString newText = t.stripWhiteSpace();
    00198     if (newText.isEmpty())
    00199        return;
    00200
    00201     // remove newlines in the to-be-pasted string as well as an eventual
    00202     // mailto: protocol
    00203     newText.replace( QRegExp("\r?\n"), " " );
    00204     if ( newText.startsWith( "mailto:" ) )
    00205         newText.remove( 0, 7 );
    00206     else if (newText.contains(" at "))
    00207     {
    00208        // Anti-spam stuff
    00209        newText.replace( QRegExp(" at "), "@" );
    00210        newText.replace( QRegExp(" dot "), "." );
    00211     }
    00212     else if (newText.contains("(at)"))
    00213     {
    00214       newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
    00215     }
    00216
    00217     QString contents = text();
    00218     int start_sel = 0;
    00219     int end_sel = 0;
    00220     int pos = cursorPosition();
    00221     if (getSelection(&start_sel, &end_sel))
    00222     {
    00223        // Cut away the selection.
    00224        if (pos > end_sel)
    00225           pos -= (end_sel - start_sel);
    00226        else if (pos > start_sel)
    00227           pos = start_sel;
    00228        contents = contents.left(start_sel) + contents.right(end_sel+1);
    00229     }
    00230
    00231     int eot = contents.length();
    00232     while ((eot > 0) && contents[eot-1].isSpace()) eot--;
    00233     if (eot == 0)
    00234     {
    00235        contents = QString::null;
    00236     }
    00237     else if (pos >= eot)
    00238     {
    00239        if (contents[eot-1] == ',')
    00240           eot--;
    00241        contents.truncate(eot);
    00242        contents += ", ";
    00243        pos = eot+2;
    00244     }
    00245
    00246     contents = contents.left(pos)+newText+contents.mid(pos);
    00247     slotSetTextAsEdited(contents);
    00248     setCursorPosition(pos+newText.length());
    00249 }
    00250
    00251 void AddressLineEdit::paste()
    00252 {
    00253     if (m_useCompletion)
    00254        m_smartPaste = true;
    00255     KLineEdit::paste();
    00256     m_smartPaste = false;
    00257 }
    00258
    00259 //-----------------------------------------------------------------------------
    00260 void AddressLineEdit::cursorAtEnd()
    00261 {
    00262     setCursorPosition( text().length() );
    00263 }
    00264
    00265 //-----------------------------------------------------------------------------
    00266 void AddressLineEdit::enableCompletion(bool enable)
    00267 {
    00268   m_useCompletion = enable;
    00269 }
    00270
    00271 //-----------------------------------------------------------------------------
    00272 void AddressLineEdit::doCompletion(bool ctrlT)
    00273 {
    00274     if ( !m_useCompletion )
    00275         return;
    00276
    00277     QString s(text());
    00278     QString prevAddr;
    00279     int n = s.findRev(',');
    00280     if (n>= 0)
    00281     {
    00282         prevAddr = s.left(n+1) + ' ';
    00283         s = s.mid(n+1,255).stripWhiteSpace();
    00284     }
    00285
    00286     KCompletionBox *box = completionBox();
    00287
    00288     if ( s.isEmpty() )
    00289     {
    00290         box->hide();
    00291         return;
    00292     }
    00293
    00294     KGlobalSettings::Completion  mode = completionMode();
    00295
    00296     if ( s_addressesDirty )
    00297         loadAddresses();
    00298
    00299     if ( ctrlT )
    00300     {
    00301         QStringList completions = s_completion->substringCompletion( s );
    00302         if (completions.count() > 1) {
    00303             m_previousAddresses = prevAddr;
    00304             box->setItems( completions );
    00305             box->setCancelledText( text() );
    00306             box->popup();
    00307         }
    00308         else if (completions.count() == 1)
    00309             slotSetTextAsEdited(prevAddr + completions.first());
    00310         else
    00311             box->hide();
    00312
    00313         cursorAtEnd();
    00314         return;
    00315     }
    00316
    00317     switch ( mode )
    00318     {
    00319         case KGlobalSettings::CompletionPopup:
    00320         {
    00321                 m_previousAddresses = prevAddr;
    00322                 QStringList items = s_completion->allMatches( s );
    00323                 items += s_completion->allMatches( "\"" + s );
    00324                 items += s_completion->substringCompletion( '<' + s );
    00325             uint beforeDollarCompletionCount = items.count();
    00326
    00327                 if( !s.contains( ' ' )) // one word, possibly given name
    00328                     items += s_completion->allMatches( "$$" + s );
    00329
    00330             if ( items.isEmpty() )
    00331                 box->hide();
    00332             else
    00333             {
    00334                 if ( items.count() > beforeDollarCompletionCount )
    00335                 {
    00336                     // remove the '$$whatever$' part
    00337                 for( QStringList::Iterator it = items.begin();
    00338                      it != items.end();
    00339                      ++it )
    00340                     {
    00341                     int pos = (*it).find( '$', 2 );
    00342                     if( pos < 0 ) // ???
    00343                         continue;
    00344                     (*it)=(*it).mid( pos + 1 );
    00345                 }
    00346                 }
    00347
    00348                 items = removeMailDupes( items );
    00349                 box->setItems( items );
    00350                 box->setCancelledText( text() );
    00351                 box->popup();
    00352             }
    00353
    00354             break;
    00355         }
    00356
    00357         case KGlobalSettings::CompletionShell:
    00358         {
    00359             QString match = s_completion->makeCompletion( s );
    00360             if ( !match.isNull() && match != s )
    00361             {
    00362                 slotSetTextAsEdited( prevAddr + match );
    00363                 cursorAtEnd();
    00364             }
    00365             break;
    00366         }
    00367
    00368         case KGlobalSettings::CompletionMan: // Short-Auto in fact
    00369         case KGlobalSettings::CompletionAuto:
    00370         {
    00371             QString match = s_completion->makeCompletion( s );
    00372             if ( !match.isNull() && match != s )
    00373             {
    00374                 QString adds = prevAddr + match;
    00375                 int curPos = cursorPosition();
    00376                 validateAndSet( adds, curPos, curPos, adds.length() );
    00377             }
    00378             break;
    00379         }
    00380
    00381         default: // fall through
    00382         case KGlobalSettings::CompletionNone:
    00383             break;
    00384     }
    00385 }
    00386
    00387 //-----------------------------------------------------------------------------
    00388 void AddressLineEdit::slotPopupCompletion( const QString& completion )
    00389 {
    00390     slotSetTextAsEdited( m_previousAddresses + completion );
    00391     cursorAtEnd();
    00392 }
    00393
    00394 //-----------------------------------------------------------------------------
    00395 void AddressLineEdit::loadAddresses()
    00396 {
    00397     s_completion->clear();
    00398     s_addressesDirty = false;
    00399
    00400     QStringList adrs = addresses();
    00401     for( QStringList::ConstIterator it = adrs.begin();
    00402          it != adrs.end();
    00403          ++it)
    00404         addAddress( *it );
    00405 }
    00406
    00407 void AddressLineEdit::addAddress( const QString& adr )
    00408 {
    00409     s_completion->addItem( adr );
    00410     int pos = adr.find( '<' );
    00411     if( pos >= 0 )
    00412     {
    00413         ++pos;
    00414         int pos2 = adr.find( pos, '>' );
    00415         if( pos2 >= 0 )
    00416             s_completion->addItem( adr.mid( pos, pos2 - pos ));
    00417     }
    00418 }
    00419
    00420 void AddressLineEdit::slotStartLDAPLookup()
    00421 {
    00422     if( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
    00423         return;
    00424     startLoadingLDAPEntries();
    00425 }
    00426
    00427 void AddressLineEdit::stopLDAPLookup()
    00428 {
    00429     s_LDAPSearch->cancelSearch();
    00430     s_LDAPLineEdit = NULL;
    00431 }
    00432
    00433 void AddressLineEdit::startLoadingLDAPEntries()
    00434 {
    00435     QString s( *s_LDAPText );
    00436     // TODO cache last?
    00437     QString prevAddr;
    00438     int n = s.findRev(',');
    00439     if (n>= 0)
    00440     {
    00441         prevAddr = s.left(n+1) + ' ';
    00442         s = s.mid(n+1,255).stripWhiteSpace();
    00443     }
    00444     if( s.length() == 0 )
    00445         return;
    00446     loadAddresses(); // TODO reuse these?
    00447     s_LDAPSearch->startSearch( s );
    00448 }
    00449
    00450 void AddressLineEdit::slotLDAPSearchData( const QStringList& adrs )
    00451 {
    00452     if( s_LDAPLineEdit != this )
    00453         return;
    00454     for( QStringList::ConstIterator it = adrs.begin();
    00455          it != adrs.end();
    00456          ++it ) {
    00457         QString name(*it);
    00458         int pos = name.find( " <" );
    00459         int pos_comma = name.find( ',' );
    00460         // put name in quotes, if we have a comma in the name
    00461         if (pos>0 && pos_comma>0 && pos_comma<pos) {
    00462                 name.insert(pos, '\"');
    00463                 name.prepend('\"');
    00464         }
    00465         addAddress( name );
    00466     }
    00467     if( hasFocus() || completionBox()->hasFocus())
    00468     {
    00469         if( completionMode() != KGlobalSettings::CompletionNone )
    00470         {
    00471             doCompletion( false );
    00472         }
    00473     }
    00474 }
    00475
    00476 void AddressLineEdit::slotSetTextAsEdited( const QString& text )
    00477 {
    00478     setText( text );
    00479     setEdited( true );
    00480 }
    00481
    00482 QStringList AddressLineEdit::removeMailDupes( const QStringList& adrs )
    00483 {
    00484     QStringList src = adrs;
    00485     qHeapSort( src );
    00486     QString last;
    00487     for( QStringList::Iterator it = src.begin();
    00488          it != src.end();
    00489          )
    00490     {
    00491         if( *it == last )
    00492         {
    00493             it = src.remove( it );
    00494             continue; // dupe
    00495         }
    00496         last = *it;
    00497         ++it;
    00498     }
    00499     return src;
    00500 }
    00501
    00502 //-----------------------------------------------------------------------------
    00503 void AddressLineEdit::dropEvent(QDropEvent *e)
    00504 {
    00505   KURL::List uriList;
    00506   if(KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ))
    00507   {
    00508     QString ct = text();
    00509     KURL::List::Iterator it = uriList.begin();
    00510     for (; it != uriList.end(); ++it)
    00511     {
    00512       if (!ct.isEmpty()) ct.append(", ");
    00513       KURL u(*it);
    00514       if ((*it).protocol() == "mailto")
    00515           ct.append( (*it).path() );
    00516       else
    00517           ct.append( (*it).url() );
    00518     }
    00519     setText(ct);
    00520     setEdited( true );
    00521   }
    00522   else {
    00523     if (m_useCompletion)
    00524        m_smartPaste = true;
    00525     QLineEdit::dropEvent(e);
    00526     m_smartPaste = false;
    00527   }
    00528 }
    00529
    00530
    00531 QStringList AddressLineEdit::addresses()
    00532 {
    00533   QStringList result;
    00534
    00535   KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
    00536   KABC::AddressBook::Iterator it;
    00537   for( it = addressBook->begin(); it != addressBook->end(); ++it ) {
    00538     QStringList emails = (*it).emails();
    00539     QString n = (*it).prefix() + " " +
    00540                 (*it).givenName() + " " +
    00541                 (*it).additionalName() + " " +
    00542                 (*it).familyName() + " " +
    00543                 (*it).suffix();
    00544     n = n.simplifyWhiteSpace();
    00545
    00546     QRegExp needQuotes("[^ 0-9A-Za-z\\x0080-\\xFFFF]");
    00547     QString endQuote("\" ");
    00548     QString empty = "";
    00549     QStringList::ConstIterator mit;
    00550     QString addr, email;
    00551
    00552     for ( mit = emails.begin(); mit != emails.end(); ++mit ) {
    00553       email = *mit;
    00554       if (!email.isEmpty()) {
    00555         if (n.isEmpty() || (email.find( '<' ) != -1))
    00556           addr = empty;
    00557         else { /* do we really need quotes around this name ? */
    00558           if (n.find(needQuotes) != -1)
    00559             addr = '"' + n + endQuote;
    00560           else
    00561             addr = n + ' ';
    00562         }
    00563
    00564         if (!addr.isEmpty() && (email.find( '<' ) == -1)
    00565             && (email.find( '>' ) == -1)
    00566             && (email.find( ',' ) == -1))
    00567           addr += '<' + email + '>';
    00568         else
    00569           addr += email;
    00570         addr = addr.stripWhiteSpace();
    00571         result.append( addr );
    00572       }
    00573     }
    00574   }
    00575   KABC::DistributionListManager manager( addressBook );
    00576   manager.load();
    00577
    00578   QStringList names = manager.listNames();
    00579   QStringList::Iterator jt;
    00580   for ( jt = names.begin(); jt != names.end(); ++jt)
    00581     result.append( *jt );
    00582   result.sort();
    00583
    00584   return result;
    00585 }
    00586
    00587 #include "addresslineedit.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:29:18 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001