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(
userCancelled(
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(
"kabldaprc",
false,
false ) );
00143
00144
return s_config;
00145 }
00146
00147 void AddressLineEdit::setFont(
const QFont& font )
00148 {
00149 KLineEdit::setFont( font );
00150
if ( m_useCompletion )
00151 completionBox()->setFont( font );
00152 }
00153
00154
00155
void AddressLineEdit::keyPressEvent(
QKeyEvent *e)
00156 {
00157
bool accept =
false;
00158
00159
if (
KStdAccel::shortcut(KStdAccel::SubstringCompletion).
contains(
KKey(e)))
00160 {
00161 doCompletion(
true);
00162 accept =
true;
00163 }
00164
else if (
KStdAccel::shortcut(KStdAccel::TextCompletion).
contains(
KKey(e)))
00165 {
00166
int len = text().length();
00167
00168
if (len == cursorPosition())
00169 {
00170 doCompletion(
true);
00171 accept =
true;
00172 }
00173 }
00174
00175
if( !accept )
00176
KLineEdit::keyPressEvent( e );
00177
00178
if( e->isAccepted())
00179 {
00180
if( m_useCompletion && s_LDAPTimer != NULL )
00181 {
00182
if( *s_LDAPText != text())
00183 stopLDAPLookup();
00184 *s_LDAPText = text();
00185 s_LDAPLineEdit =
this;
00186 s_LDAPTimer->start( 500,
true );
00187 }
00188 }
00189 }
00190
00191
void AddressLineEdit::mouseReleaseEvent(
QMouseEvent * e )
00192 {
00193
if (m_useCompletion && (e->button() == MidButton))
00194 {
00195 m_smartPaste =
true;
00196 KLineEdit::mouseReleaseEvent(e);
00197 m_smartPaste =
false;
00198
return;
00199 }
00200 KLineEdit::mouseReleaseEvent(e);
00201 }
00202
00203
void AddressLineEdit::insert(
const QString &t)
00204 {
00205
if (!m_smartPaste)
00206 {
00207 KLineEdit::insert(t);
00208
return;
00209 }
00210
QString newText = t.stripWhiteSpace();
00211
if (newText.isEmpty())
00212
return;
00213
00214
00215
00216 newText.replace(
QRegExp(
"\r?\n"),
", " );
00217
if ( newText.startsWith(
"mailto:" ) )
00218 {
00219
KURL u(newText);
00220 newText = u.
path();
00221 }
00222
else if (newText.find(
" at ") != -1)
00223 {
00224
00225 newText.replace(
" at ",
"@" );
00226 newText.replace(
" dot ",
"." );
00227 }
00228
else if (newText.find(
"(at)") != -1)
00229 {
00230 newText.replace(
QRegExp(
"\\s*\\(at\\)\\s*"),
"@" );
00231 }
00232
00233
QString contents = text();
00234
int start_sel = 0;
00235
int end_sel = 0;
00236
int pos = cursorPosition();
00237
if (getSelection(&start_sel, &end_sel))
00238 {
00239
00240
if (pos > end_sel)
00241 pos -= (end_sel - start_sel);
00242
else if (pos > start_sel)
00243 pos = start_sel;
00244 contents = contents.left(start_sel) + contents.right(end_sel+1);
00245 }
00246
00247
int eot = contents.length();
00248
while ((eot > 0) && contents[eot-1].isSpace()) eot--;
00249
if (eot == 0)
00250 {
00251 contents = QString::null;
00252 }
00253
else if (pos >= eot)
00254 {
00255
if (contents[eot-1] ==
',')
00256 eot--;
00257 contents.truncate(eot);
00258 contents +=
", ";
00259 pos = eot+2;
00260 }
00261
00262 contents = contents.left(pos)+newText+contents.mid(pos);
00263
setText(contents);
00264 setCursorPosition(pos+newText.length());
00265 }
00266
00267
void AddressLineEdit::paste()
00268 {
00269
if (m_useCompletion)
00270 m_smartPaste =
true;
00271 KLineEdit::paste();
00272 m_smartPaste =
false;
00273 }
00274
00275
00276 void AddressLineEdit::cursorAtEnd()
00277 {
00278 setCursorPosition( text().length() );
00279 }
00280
00281
00282 void AddressLineEdit::enableCompletion(
bool enable)
00283 {
00284 m_useCompletion = enable;
00285 }
00286
00287
00288
void AddressLineEdit::doCompletion(
bool ctrlT)
00289 {
00290
if ( !m_useCompletion )
00291
return;
00292
00293
QString prevAddr;
00294
00295
QString s(text());
00296
int n = s.findRev(
',');
00297
00298
if (n >= 0)
00299 {
00300 n++;
00301
00302
int len = s.length();
00303
00304
00305
while( n < len && s[n].isSpace() )
00306 n++;
00307
00308 prevAddr = s.left(n);
00309 s = s.mid(n,255).stripWhiteSpace();
00310 }
00311
00312
if ( s_addressesDirty )
00313
loadAddresses();
00314
00315
if ( ctrlT )
00316 {
00317
QStringList completions = s_completion->
substringCompletion( s );
00318
if (completions.count() > 1) {
00319 m_previousAddresses = prevAddr;
00320 setCompletedItems( completions );
00321 }
00322
else if (completions.count() == 1)
00323
setText(prevAddr + completions.first());
00324
00325
cursorAtEnd();
00326
return;
00327 }
00328
00329
KGlobalSettings::Completion mode =
completionMode();
00330
00331
switch ( mode )
00332 {
00333
case KGlobalSettings::CompletionPopupAuto:
00334 {
00335
if (s.isEmpty())
00336
break;
00337 }
00338
case KGlobalSettings::CompletionPopup:
00339 {
00340 m_previousAddresses = prevAddr;
00341
QStringList items = s_completion->
allMatches( s );
00342 items += s_completion->
allMatches(
"\"" + s );
00343 items += s_completion->
substringCompletion(
'<' + s );
00344 uint beforeDollarCompletionCount = items.count();
00345
00346
if( s.find(
' ' ) == -1 )
00347 items += s_completion->
allMatches(
"$$" + s );
00348
00349
if ( !items.isEmpty() )
00350 {
00351
if ( items.count() > beforeDollarCompletionCount )
00352 {
00353
00354
for( QStringList::Iterator it = items.begin();
00355 it != items.end();
00356 ++it )
00357 {
00358
int pos = (*it).find(
'$', 2 );
00359
if( pos < 0 )
00360
continue;
00361 (*it)=(*it).mid( pos + 1 );
00362 }
00363 }
00364
00365 items = removeMailDupes( items );
00366
00367
00368
00369
00370
00371
bool autoSuggest = (mode !=
KGlobalSettings::CompletionPopupAuto);
00372
setCompletedItems( items, autoSuggest );
00373
00374
if (!autoSuggest)
00375 {
00376
int index = items.first().find( s );
00377
QString newText = prevAddr + items.first().mid( index );
00378
00379
00380
setUserSelection(
false);
00381
setCompletedText(newText,
true);
00382 }
00383 }
00384
00385
break;
00386 }
00387
00388
case KGlobalSettings::CompletionShell:
00389 {
00390
QString match = s_completion->
makeCompletion( s );
00391
if ( !match.isNull() && match != s )
00392 {
00393
setText( prevAddr + match );
00394
cursorAtEnd();
00395 }
00396
break;
00397 }
00398
00399
case KGlobalSettings::CompletionMan:
00400
case KGlobalSettings::CompletionAuto:
00401 {
00402
if (!s.isEmpty())
00403 {
00404
QString match = s_completion->
makeCompletion( s );
00405
if ( !match.isNull() && match != s )
00406 {
00407
QString adds = prevAddr + match;
00408
setCompletedText( adds );
00409 }
00410
break;
00411 }
00412 }
00413
case KGlobalSettings::CompletionNone:
00414
default:
00415
break;
00416 }
00417 }
00418
00419
00420
void AddressLineEdit::slotPopupCompletion(
const QString& completion )
00421 {
00422
setText( m_previousAddresses + completion );
00423
cursorAtEnd();
00424 }
00425
00426
00427 void AddressLineEdit::loadAddresses()
00428 {
00429 s_completion->
clear();
00430 s_addressesDirty =
false;
00431
00432
QStringList adrs = addresses();
00433
for( QStringList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it)
00434 addAddress( *it );
00435 }
00436
00437
void AddressLineEdit::addAddress(
const QString& adr )
00438 {
00439 s_completion->
addItem( adr );
00440
int pos = adr.find(
'<' );
00441
if( pos >= 0 )
00442 {
00443 ++pos;
00444
int pos2 = adr.find( pos,
'>' );
00445
if( pos2 >= 0 )
00446 s_completion->
addItem( adr.mid( pos, pos2 - pos ));
00447 }
00448 }
00449
00450
void AddressLineEdit::slotStartLDAPLookup()
00451 {
00452
if( !s_LDAPSearch->
isAvailable() || s_LDAPLineEdit !=
this )
00453
return;
00454 startLoadingLDAPEntries();
00455 }
00456
00457
void AddressLineEdit::stopLDAPLookup()
00458 {
00459 s_LDAPSearch->
cancelSearch();
00460 s_LDAPLineEdit = NULL;
00461 }
00462
00463
void AddressLineEdit::startLoadingLDAPEntries()
00464 {
00465
QString s( *s_LDAPText );
00466
00467
QString prevAddr;
00468
int n = s.findRev(
',');
00469
if (n>= 0)
00470 {
00471 prevAddr = s.left(n+1) +
' ';
00472 s = s.mid(n+1,255).stripWhiteSpace();
00473 }
00474
if( s.length() == 0 )
00475
return;
00476
00477
loadAddresses();
00478 s_LDAPSearch->
startSearch( s );
00479 }
00480
00481
void AddressLineEdit::slotLDAPSearchData(
const QStringList& adrs )
00482 {
00483
if( s_LDAPLineEdit !=
this )
00484
return;
00485
for( QStringList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
00486
QString name(*it);
00487
int pos =
name.find(
" <" );
00488
int pos_comma =
name.find(
',' );
00489
00490
if (pos>0 && pos_comma>0 && pos_comma<pos) {
00491
name.insert(pos,
'\"');
00492
name.prepend(
'\"');
00493 }
00494 addAddress( name );
00495 }
00496
00497
if( hasFocus() || completionBox()->hasFocus())
00498 {
00499
if(
completionMode() !=
KGlobalSettings::CompletionNone )
00500 {
00501 doCompletion(
false );
00502 }
00503 }
00504 }
00505
00506
QStringList AddressLineEdit::removeMailDupes(
const QStringList& adrs )
00507 {
00508
QStringList src = adrs;
00509 qHeapSort( src );
00510
QString last;
00511
for( QStringList::Iterator it = src.begin(); it != src.end(); ) {
00512
if( *it == last )
00513 {
00514 it = src.remove( it );
00515
continue;
00516 }
00517 last = *it;
00518 ++it;
00519 }
00520
return src;
00521 }
00522
00523
00524
void AddressLineEdit::dropEvent(
QDropEvent *e)
00525 {
00526
KURL::List uriList;
00527
if(KURLDrag::canDecode(e) &&
KURLDrag::decode( e, uriList ))
00528 {
00529
QString ct = text();
00530 KURL::List::Iterator it = uriList.begin();
00531
for (; it != uriList.end(); ++it)
00532 {
00533
if (!ct.isEmpty()) ct.append(
", ");
00534
KURL u(*it);
00535
if ((*it).protocol() ==
"mailto")
00536 ct.append( (*it).path() );
00537
else
00538 ct.append( (*it).url() );
00539 }
00540
setText(ct);
00541 setEdited(
true );
00542 }
00543
else {
00544
if (m_useCompletion)
00545 m_smartPaste =
true;
00546 QLineEdit::dropEvent(e);
00547 m_smartPaste =
false;
00548 }
00549 }
00550
00551
00552
QStringList AddressLineEdit::addresses()
00553 {
00554 QApplication::setOverrideCursor( KCursor::waitCursor() );
00555
00556
QStringList result;
00557
QString space(
" ");
00558
QRegExp needQuotes(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]");
00559
QString endQuote(
"\" ");
00560
QString addr, email;
00561
00562
KABC::AddressBook *addressBook =
KABC::StdAddressBook::self();
00563
KABC::AddressBook::Iterator it;
00564
for( it = addressBook->
begin(); it != addressBook->
end(); ++it ) {
00565
QStringList emails = (*it).emails();
00566
00567
QString n = (*it).prefix() + space +
00568 (*it).givenName() + space +
00569 (*it).additionalName() + space +
00570 (*it).familyName() + space +
00571 (*it).suffix();
00572
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
00601
KABC::DistributionListManager manager( addressBook );
00602 manager.
load();
00603 result += manager.
listNames();
00604
00605 QApplication::restoreOverrideCursor();
00606
00607
return result;
00608 }
00609
00610
#include "addresslineedit.moc"