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 <qapplication.h>
00029 #include <qobject.h>
00030 #include <qptrlist.h>
00031 #include <qregexp.h>
00032 #include <qevent.h>
00033 #include <qdragobject.h>
00034
00035 #include <kcompletionbox.h>
00036 #include <kconfig.h>
00037 #include <kcursor.h>
00038 #include <kstandarddirs.h>
00039 #include <kstaticdeleter.h>
00040 #include <kstdaccel.h>
00041 #include <kurldrag.h>
00042
00043 #include <kabc/stdaddressbook.h>
00044 #include <kabc/distributionlist.h>
00045 #include "ldapclient.h"
00046
00047 #include <kdebug.h>
00048
00049
00050
00051
00052
00053
00054
00055
00056 using namespace KABC;
00057
00058 KCompletion * AddressLineEdit::s_completion = 0L;
00059 bool AddressLineEdit::s_addressesDirty = false;
00060 QTimer* AddressLineEdit::s_LDAPTimer = 0L;
00061 LdapSearch* AddressLineEdit::s_LDAPSearch = 0L;
00062 QString* AddressLineEdit::s_LDAPText = 0L;
00063 AddressLineEdit* AddressLineEdit::s_LDAPLineEdit = 0L;
00064 KConfig *AddressLineEdit::s_config = 0L;
00065
00066 static KStaticDeleter<KCompletion> completionDeleter;
00067 static KStaticDeleter<QTimer> ldapTimerDeleter;
00068 static KStaticDeleter<LdapSearch> ldapSearchDeleter;
00069 static KStaticDeleter<QString> ldapTextDeleter;
00070 static KStaticDeleter<KConfig> configDeleter;
00071
00072 AddressLineEdit::AddressLineEdit(QWidget* parent,
00073 bool useCompletion,
00074 const char *name)
00075 : KLineEdit(parent,name)
00076 {
00077 m_useCompletion = useCompletion;
00078 m_completionInitialized = false;
00079 m_smartPaste = false;
00080
00081 init();
00082
00083
00084
00085
00086
00087 if (m_useCompletion)
00088 s_addressesDirty = true;
00089 }
00090
00091
00092
00093 void AddressLineEdit::init()
00094 {
00095 if ( !s_completion ) {
00096 completionDeleter.setObject( s_completion, new KCompletion() );
00097 s_completion->setOrder( KCompletion::Sorted );
00098 s_completion->setIgnoreCase( true );
00099 }
00100
00101 if( m_useCompletion ) {
00102 if( !s_LDAPTimer ) {
00103 ldapTimerDeleter.setObject( s_LDAPTimer, new QTimer );
00104 ldapSearchDeleter.setObject( s_LDAPSearch, new LdapSearch );
00105 ldapTextDeleter.setObject( s_LDAPText, new QString );
00106 }
00107 connect( s_LDAPTimer, SIGNAL( timeout()), SLOT( slotStartLDAPLookup()));
00108 connect( s_LDAPSearch, SIGNAL( searchData( const QStringList& )),
00109 SLOT( slotLDAPSearchData( const QStringList& )));
00110 }
00111
00112 if ( m_useCompletion && !m_completionInitialized )
00113 {
00114 setCompletionObject( s_completion, false );
00115 connect( this, SIGNAL( completion(const QString&)),
00116 this, SLOT(slotCompletion() ));
00117
00118 KCompletionBox *box = completionBox();
00119 connect( box, SIGNAL( highlighted( const QString& )),
00120 this, SLOT( slotPopupCompletion( const QString& ) ));
00121 connect( box, SIGNAL( userCancelled( const QString& )),
00122 SLOT( slotSetTextAsEdited( const QString& )));
00123
00124 m_completionInitialized = true;
00125
00126
00127
00128
00129 }
00130 }
00131
00132
00133 AddressLineEdit::~AddressLineEdit()
00134 {
00135 }
00136
00137
00138
00139 KConfig* AddressLineEdit::config()
00140 {
00141 if ( !s_config )
00142 configDeleter.setObject( s_config, new KConfig( locateLocal( "config",
00143 "kabldaprc" ) ) );
00144
00145 return s_config;
00146 }
00147
00148 void AddressLineEdit::setFont( const QFont& font )
00149 {
00150 KLineEdit::setFont( font );
00151 if ( m_useCompletion )
00152 completionBox()->setFont( font );
00153 }
00154
00155
00156 void AddressLineEdit::keyPressEvent(QKeyEvent *e)
00157 {
00158 bool accept = false;
00159
00160 if (KStdAccel::shortcut(KStdAccel::SubstringCompletion).contains(KKey(e)))
00161 {
00162 doCompletion(true);
00163 accept = true;
00164 }
00165 else if (e->state()==ControlButton && e->key() == Key_Right)
00166 {
00167 if ((int)text().length() == cursorPosition())
00168 {
00169 doCompletion(true);
00170 accept = true;
00171 }
00172 }
00173 else if (e->state()==ControlButton && e->key() == Key_V)
00174 {
00175 if (m_useCompletion)
00176 m_smartPaste = true;
00177 paste();
00178 m_smartPaste = false;
00179 accept = true;
00180 }
00181
00182 if( !accept )
00183 KLineEdit::keyPressEvent( e );
00184
00185 if( e->isAccepted())
00186 {
00187 if( m_useCompletion && s_LDAPTimer != NULL )
00188 {
00189 if( *s_LDAPText != text())
00190 stopLDAPLookup();
00191 *s_LDAPText = text();
00192 s_LDAPLineEdit = this;
00193 s_LDAPTimer->start( 500, true );
00194 }
00195 }
00196 }
00197
00198 void AddressLineEdit::mouseReleaseEvent( QMouseEvent * e )
00199 {
00200 if (m_useCompletion && (e->button() == MidButton))
00201 {
00202 m_smartPaste = true;
00203 KLineEdit::mouseReleaseEvent(e);
00204 m_smartPaste = false;
00205 return;
00206 }
00207 KLineEdit::mouseReleaseEvent(e);
00208 }
00209
00210 void AddressLineEdit::insert(const QString &t)
00211 {
00212 if (!m_smartPaste)
00213 {
00214 KLineEdit::insert(t);
00215 return;
00216 }
00217 QString newText = t.stripWhiteSpace();
00218 if (newText.isEmpty())
00219 return;
00220
00221
00222
00223 newText.replace( QRegExp("\r?\n"), ", " );
00224 if ( newText.startsWith( "mailto:" ) )
00225 {
00226 KURL u(newText);
00227 newText = u.path();
00228 }
00229 else if (newText.find(" at ") != -1)
00230 {
00231
00232 newText.replace( " at ", "@" );
00233 newText.replace( " dot ", "." );
00234 }
00235 else if (newText.find("(at)") != -1)
00236 {
00237 newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
00238 }
00239
00240 QString contents = text();
00241 int start_sel = 0;
00242 int end_sel = 0;
00243 int pos = cursorPosition();
00244 if (getSelection(&start_sel, &end_sel))
00245 {
00246
00247 if (pos > end_sel)
00248 pos -= (end_sel - start_sel);
00249 else if (pos > start_sel)
00250 pos = start_sel;
00251 contents = contents.left(start_sel) + contents.right(end_sel+1);
00252 }
00253
00254 int eot = contents.length();
00255 while ((eot > 0) && contents[eot-1].isSpace()) eot--;
00256 if (eot == 0)
00257 {
00258 contents = QString::null;
00259 }
00260 else if (pos >= eot)
00261 {
00262 if (contents[eot-1] == ',')
00263 eot--;
00264 contents.truncate(eot);
00265 contents += ", ";
00266 pos = eot+2;
00267 }
00268
00269 contents = contents.left(pos)+newText+contents.mid(pos);
00270 slotSetTextAsEdited(contents);
00271 setCursorPosition(pos+newText.length());
00272 }
00273
00274 void AddressLineEdit::paste()
00275 {
00276 if (m_useCompletion)
00277 m_smartPaste = true;
00278 KLineEdit::paste();
00279 m_smartPaste = false;
00280 }
00281
00282
00283 void AddressLineEdit::cursorAtEnd()
00284 {
00285 setCursorPosition( text().length() );
00286 }
00287
00288
00289 void AddressLineEdit::enableCompletion(bool enable)
00290 {
00291 m_useCompletion = enable;
00292 }
00293
00294
00295 void AddressLineEdit::doCompletion(bool ctrlT)
00296 {
00297 if ( !m_useCompletion )
00298 return;
00299
00300 QString s(text());
00301 QString prevAddr;
00302 int n = s.findRev(',');
00303 if (n>= 0)
00304 {
00305 prevAddr = s.left(n+1) + ' ';
00306 s = s.mid(n+1,255).stripWhiteSpace();
00307 }
00308
00309 KCompletionBox *box = completionBox();
00310
00311 if ( s.isEmpty() )
00312 {
00313 box->hide();
00314 return;
00315 }
00316
00317 KGlobalSettings::Completion mode = completionMode();
00318
00319 if ( s_addressesDirty )
00320 loadAddresses();
00321
00322 if ( ctrlT )
00323 {
00324 QStringList completions = s_completion->substringCompletion( s );
00325 if (completions.count() > 1) {
00326 m_previousAddresses = prevAddr;
00327 box->setItems( completions );
00328 box->setCancelledText( text() );
00329 box->popup();
00330 }
00331 else if (completions.count() == 1)
00332 slotSetTextAsEdited(prevAddr + completions.first());
00333 else
00334 box->hide();
00335
00336 cursorAtEnd();
00337 return;
00338 }
00339
00340 switch ( mode )
00341 {
00342 case KGlobalSettings::CompletionPopup:
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 uint beforeDollarCompletionCount = items.count();
00349
00350 if( s.find( ' ' ) == -1 )
00351 items += s_completion->allMatches( "$$" + s );
00352
00353 if ( items.isEmpty() )
00354 box->hide();
00355 else
00356 {
00357 if ( items.count() > beforeDollarCompletionCount )
00358 {
00359
00360 for( QStringList::Iterator it = items.begin();
00361 it != items.end();
00362 ++it )
00363 {
00364 int pos = (*it).find( '$', 2 );
00365 if( pos < 0 )
00366 continue;
00367 (*it)=(*it).mid( pos + 1 );
00368 }
00369 }
00370
00371 items = removeMailDupes( items );
00372 box->setItems( items );
00373 box->setCancelledText( text() );
00374 box->popup();
00375 }
00376
00377 break;
00378 }
00379
00380 case KGlobalSettings::CompletionShell:
00381 {
00382 QString match = s_completion->makeCompletion( s );
00383 if ( !match.isNull() && match != s )
00384 {
00385 slotSetTextAsEdited( prevAddr + match );
00386 cursorAtEnd();
00387 }
00388 break;
00389 }
00390
00391 case KGlobalSettings::CompletionMan:
00392 case KGlobalSettings::CompletionAuto:
00393 {
00394 QString match = s_completion->makeCompletion( s );
00395 if ( !match.isNull() && match != s )
00396 {
00397 QString adds = prevAddr + match;
00398 int curPos = cursorPosition();
00399 validateAndSet( adds, curPos, curPos, adds.length() );
00400 }
00401 break;
00402 }
00403
00404 default:
00405 case KGlobalSettings::CompletionNone:
00406 break;
00407 }
00408 }
00409
00410
00411 void AddressLineEdit::slotPopupCompletion( const QString& completion )
00412 {
00413 slotSetTextAsEdited( m_previousAddresses + completion );
00414 cursorAtEnd();
00415 }
00416
00417
00418 void AddressLineEdit::loadAddresses()
00419 {
00420 s_completion->clear();
00421 s_addressesDirty = false;
00422
00423 QStringList adrs = addresses();
00424 for( QStringList::ConstIterator it = adrs.begin();
00425 it != adrs.end();
00426 ++it)
00427 addAddress( *it );
00428 }
00429
00430 void AddressLineEdit::addAddress( const QString& adr )
00431 {
00432 s_completion->addItem( adr );
00433 int pos = adr.find( '<' );
00434 if( pos >= 0 )
00435 {
00436 ++pos;
00437 int pos2 = adr.find( pos, '>' );
00438 if( pos2 >= 0 )
00439 s_completion->addItem( adr.mid( pos, pos2 - pos ));
00440 }
00441 }
00442
00443 void AddressLineEdit::slotStartLDAPLookup()
00444 {
00445 if( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
00446 return;
00447 startLoadingLDAPEntries();
00448 }
00449
00450 void AddressLineEdit::stopLDAPLookup()
00451 {
00452 s_LDAPSearch->cancelSearch();
00453 s_LDAPLineEdit = NULL;
00454 }
00455
00456 void AddressLineEdit::startLoadingLDAPEntries()
00457 {
00458 QString s( *s_LDAPText );
00459
00460 QString prevAddr;
00461 int n = s.findRev(',');
00462 if (n>= 0)
00463 {
00464 prevAddr = s.left(n+1) + ' ';
00465 s = s.mid(n+1,255).stripWhiteSpace();
00466 }
00467 if( s.length() == 0 )
00468 return;
00469 loadAddresses();
00470 s_LDAPSearch->startSearch( s );
00471 }
00472
00473 void AddressLineEdit::slotLDAPSearchData( const QStringList& adrs )
00474 {
00475 if( s_LDAPLineEdit != this )
00476 return;
00477 for( QStringList::ConstIterator it = adrs.begin();
00478 it != adrs.end();
00479 ++it ) {
00480 QString name(*it);
00481 int pos = name.find( " <" );
00482 int pos_comma = name.find( ',' );
00483
00484 if (pos>0 && pos_comma>0 && pos_comma<pos) {
00485 name.insert(pos, '\"');
00486 name.prepend('\"');
00487 }
00488 addAddress( name );
00489 }
00490 if( hasFocus() || completionBox()->hasFocus())
00491 {
00492 if( completionMode() != KGlobalSettings::CompletionNone )
00493 {
00494 doCompletion( false );
00495 }
00496 }
00497 }
00498
00499 void AddressLineEdit::slotSetTextAsEdited( const QString& text )
00500 {
00501 setText( text );
00502 setEdited( true );
00503 }
00504
00505 QStringList AddressLineEdit::removeMailDupes( const QStringList& adrs )
00506 {
00507 QStringList src = adrs;
00508 qHeapSort( src );
00509 QString last;
00510 for( QStringList::Iterator it = src.begin();
00511 it != src.end();
00512 )
00513 {
00514 if( *it == last )
00515 {
00516 it = src.remove( it );
00517 continue;
00518 }
00519 last = *it;
00520 ++it;
00521 }
00522 return src;
00523 }
00524
00525
00526 void AddressLineEdit::dropEvent(QDropEvent *e)
00527 {
00528 KURL::List uriList;
00529 if(KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ))
00530 {
00531 QString ct = text();
00532 KURL::List::Iterator it = uriList.begin();
00533 for (; it != uriList.end(); ++it)
00534 {
00535 if (!ct.isEmpty()) ct.append(", ");
00536 KURL u(*it);
00537 if ((*it).protocol() == "mailto")
00538 ct.append( (*it).path() );
00539 else
00540 ct.append( (*it).url() );
00541 }
00542 setText(ct);
00543 setEdited( true );
00544 }
00545 else {
00546 if (m_useCompletion)
00547 m_smartPaste = true;
00548 QLineEdit::dropEvent(e);
00549 m_smartPaste = false;
00550 }
00551 }
00552
00553
00554 QStringList AddressLineEdit::addresses()
00555 {
00556 QApplication::setOverrideCursor( KCursor::waitCursor() );
00557
00558 QStringList result;
00559 QString space(" ");
00560 QRegExp needQuotes("[^ 0-9A-Za-z\\x0080-\\xFFFF]");
00561 QString endQuote("\" ");
00562 QString addr, email;
00563
00564 KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00565 KABC::AddressBook::Iterator it;
00566 for( it = addressBook->begin(); it != addressBook->end(); ++it ) {
00567 QStringList emails = (*it).emails();
00568 QString n = (*it).prefix() + space +
00569 (*it).givenName() + space +
00570 (*it).additionalName() + space +
00571 (*it).familyName() + space +
00572 (*it).suffix();
00573 n = n.simplifyWhiteSpace();
00574
00575 QStringList::ConstIterator mit;
00576
00577 for ( mit = emails.begin(); mit != emails.end(); ++mit ) {
00578 email = *mit;
00579 if (!email.isEmpty()) {
00580 if (n.isEmpty() || (email.find( '<' ) != -1))
00581 addr = QString::null;
00582 else {
00583 if (n.find(needQuotes) != -1)
00584 addr = '"' + n + endQuote;
00585 else
00586 addr = n + space;
00587 }
00588
00589 if (!addr.isEmpty() && (email.find( '<' ) == -1)
00590 && (email.find( '>' ) == -1)
00591 && (email.find( ',' ) == -1))
00592 addr += '<' + email + '>';
00593 else
00594 addr += email;
00595 addr = addr.stripWhiteSpace();
00596 result.append( addr );
00597 }
00598 }
00599 }
00600 KABC::DistributionListManager manager( addressBook );
00601 manager.load();
00602 result += manager.listNames();
00603
00604 QApplication::restoreOverrideCursor();
00605
00606 return result;
00607 }
00608
00609 #include "addresslineedit.moc"