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