addresslineedit.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #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
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
00073
00074
00075
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 );
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;
00114
00115
00116
00117
00118
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())
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
00202
00203 newText.replace( QRegExp("\r?\n"), " " );
00204 if ( newText.startsWith( "mailto:" ) )
00205 newText.remove( 0, 7 );
00206 else if (newText.contains(" at "))
00207 {
00208
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
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 QString match;
00300 int curPos = cursorPosition();
00301 if ( mode != KGlobalSettings::CompletionNone )
00302 {
00303 match = s_completion->makeCompletion( s );
00304 if (match.isNull() && mode == KGlobalSettings::CompletionPopup)
00305 match = s_completion->makeCompletion( "\"" + s );
00306 if (match.isNull() && mode == KGlobalSettings::CompletionPopup)
00307 match = s_completion->makeCompletion( "$$" + s );
00308 }
00309
00310 kdDebug() << "** completion for: " << s << " : " << match << endl;
00311
00312 if ( ctrlT )
00313 {
00314 QStringList addresses = s_completion->items();
00315 QStringList::Iterator it = addresses.begin();
00316 QStringList completions;
00317 for (; it != addresses.end(); ++it)
00318 {
00319 if ((*it).find(s,0,false) >= 0)
00320 completions.append( *it );
00321 }
00322
00323 if (completions.count() > 1) {
00324 m_previousAddresses = prevAddr;
00325 box->setItems( completions );
00326 box->setCancelledText( text() );
00327 box->popup();
00328 }
00329 else if (completions.count() == 1)
00330 slotSetTextAsEdited(prevAddr + completions.first());
00331 else
00332 box->hide();
00333
00334 cursorAtEnd();
00335 return;
00336 }
00337
00338 switch ( mode )
00339 {
00340 case KGlobalSettings::CompletionPopup:
00341 {
00342 if ( !match.isNull() )
00343 {
00344 m_previousAddresses = prevAddr;
00345 QStringList items = s_completion->allMatches( s );
00346 items += s_completion->allMatches( "\"" + s );
00347 items += s_completion->substringCompletion( '<' + s );
00348 if( !s.contains( ' ' ))
00349 items += s_completion->allMatches( "$$" + s );
00350 for( QStringList::Iterator it = items.begin();
00351 it != items.end();
00352 ++it )
00353 {
00354 int pos = (*it).find( '$', 2 );
00355 if( pos < 0 )
00356 continue;
00357 (*it)=(*it).mid( pos + 1 );
00358 }
00359 items = removeMailDupes( items );
00360 box->setItems( items );
00361 box->setCancelledText( text() );
00362 box->popup();
00363 }
00364 else
00365 box->hide();
00366
00367 break;
00368 }
00369
00370 case KGlobalSettings::CompletionShell:
00371 {
00372 if ( !match.isNull() && match != s )
00373 {
00374 slotSetTextAsEdited( prevAddr + match );
00375 cursorAtEnd();
00376 }
00377 break;
00378 }
00379
00380 case KGlobalSettings::CompletionMan:
00381 case KGlobalSettings::CompletionAuto:
00382 {
00383 if ( !match.isNull() && match != s )
00384 {
00385 QString adds = prevAddr + match;
00386 validateAndSet( adds, curPos, curPos, adds.length() );
00387 }
00388 break;
00389 }
00390
00391 default:
00392 case KGlobalSettings::CompletionNone:
00393 break;
00394 }
00395 }
00396
00397
00398 void AddressLineEdit::slotPopupCompletion( const QString& completion )
00399 {
00400 slotSetTextAsEdited( m_previousAddresses + completion );
00401 cursorAtEnd();
00402 }
00403
00404
00405 void AddressLineEdit::loadAddresses()
00406 {
00407 s_completion->clear();
00408 s_addressesDirty = false;
00409
00410 QStringList adrs = addresses();
00411 for( QStringList::ConstIterator it = adrs.begin();
00412 it != adrs.end();
00413 ++it)
00414 addAddress( *it );
00415 }
00416
00417 void AddressLineEdit::addAddress( const QString& adr )
00418 {
00419 s_completion->addItem( adr );
00420 int pos = adr.find( '<' );
00421 if( pos >= 0 )
00422 {
00423 ++pos;
00424 int pos2 = adr.find( pos, '>' );
00425 if( pos2 >= 0 )
00426 s_completion->addItem( adr.mid( pos, pos2 - pos ));
00427 }
00428 }
00429
00430 void AddressLineEdit::slotStartLDAPLookup()
00431 {
00432 if( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
00433 return;
00434 startLoadingLDAPEntries();
00435 }
00436
00437 void AddressLineEdit::stopLDAPLookup()
00438 {
00439 s_LDAPSearch->cancelSearch();
00440 s_LDAPLineEdit = NULL;
00441 }
00442
00443 void AddressLineEdit::startLoadingLDAPEntries()
00444 {
00445 QString s( *s_LDAPText );
00446
00447 QString prevAddr;
00448 int n = s.findRev(',');
00449 if (n>= 0)
00450 {
00451 prevAddr = s.left(n+1) + ' ';
00452 s = s.mid(n+1,255).stripWhiteSpace();
00453 }
00454 if( s.length() == 0 )
00455 return;
00456 loadAddresses();
00457 s_LDAPSearch->startSearch( s );
00458 }
00459
00460 void AddressLineEdit::slotLDAPSearchData( const QStringList& adrs )
00461 {
00462 if( s_LDAPLineEdit != this )
00463 return;
00464 for( QStringList::ConstIterator it = adrs.begin();
00465 it != adrs.end();
00466 ++it )
00467 addAddress( *it );
00468 if( hasFocus() || completionBox()->hasFocus())
00469 {
00470
00471
00472 if( completionMode() != KGlobalSettings::CompletionShell
00473 && completionMode() != KGlobalSettings::CompletionNone )
00474 {
00475 doCompletion( false );
00476 }
00477 }
00478 }
00479
00480 void AddressLineEdit::slotSetTextAsEdited( const QString& text )
00481 {
00482 setText( text );
00483 setEdited( true );
00484 }
00485
00486 QStringList AddressLineEdit::removeMailDupes( const QStringList& adrs )
00487 {
00488 QStringList src = adrs;
00489 qHeapSort( src );
00490 QString last;
00491 for( QStringList::Iterator it = src.begin();
00492 it != src.end();
00493 )
00494 {
00495 if( *it == last )
00496 {
00497 it = src.remove( it );
00498 continue;
00499 }
00500 last = *it;
00501 ++it;
00502 }
00503 return src;
00504 }
00505
00506
00507 void AddressLineEdit::dropEvent(QDropEvent *e)
00508 {
00509 KURL::List uriList;
00510 if(KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ))
00511 {
00512 QString ct = text();
00513 KURL::List::Iterator it = uriList.begin();
00514 for (; it != uriList.end(); ++it)
00515 {
00516 if (!ct.isEmpty()) ct.append(", ");
00517 KURL u(*it);
00518 if ((*it).protocol() == "mailto")
00519 ct.append( (*it).path() );
00520 else
00521 ct.append( (*it).url() );
00522 }
00523 setText(ct);
00524 setEdited( true );
00525 }
00526 else {
00527 if (m_useCompletion)
00528 m_smartPaste = true;
00529 QLineEdit::dropEvent(e);
00530 m_smartPaste = false;
00531 }
00532 }
00533
00534
00535 QStringList AddressLineEdit::addresses()
00536 {
00537 QStringList result;
00538
00539 KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00540 KABC::AddressBook::Iterator it;
00541 for( it = addressBook->begin(); it != addressBook->end(); ++it ) {
00542 QStringList emails = (*it).emails();
00543 QString n = (*it).prefix() + " " +
00544 (*it).givenName() + " " +
00545 (*it).additionalName() + " " +
00546 (*it).familyName() + " " +
00547 (*it).suffix();
00548 n = n.simplifyWhiteSpace();
00549
00550 QRegExp needQuotes("[^ 0-9A-Za-z\\x0080-\\xFFFF]");
00551 QString endQuote = "\" ";
00552 QString empty = "";
00553 QStringList::ConstIterator mit;
00554 QString addr, email;
00555
00556 for ( mit = emails.begin(); mit != emails.end(); ++mit ) {
00557 email = *mit;
00558 if (!email.isEmpty()) {
00559 if (n.isEmpty() || (email.find( '<' ) != -1))
00560 addr = empty;
00561 else {
00562 if (n.find(needQuotes) != -1)
00563 addr = '"' + n + endQuote;
00564 else
00565 addr = n + ' ';
00566 }
00567
00568 if (!addr.isEmpty() && (email.find( '<' ) == -1)
00569 && (email.find( '>' ) == -1)
00570 && (email.find( ',' ) == -1))
00571 addr += '<' + email + '>';
00572 else
00573 addr += email;
00574 addr = addr.stripWhiteSpace();
00575 result.append( addr );
00576 }
00577 }
00578 }
00579 KABC::DistributionListManager manager( addressBook );
00580 manager.load();
00581
00582 QStringList names = manager.listNames();
00583 QStringList::Iterator jt;
00584 for ( jt = names.begin(); jt != names.end(); ++jt)
00585 result.append( *jt );
00586 result.sort();
00587
00588 return result;
00589 }
00590
00591 #include "addresslineedit.moc"
This file is part of the documentation for kdelibs Version 3.1.0.