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"