• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeabc
 

tdeabc

  • tdeabc
addresslineedit.cpp
1/*
2 This file is part of libtdeabc.
3 Copyright (c) 2002 Helge Deller <deller@gmx.de>
4 2002 Lubos Lunak <llunak@suse.cz>
5 2001,2003 Carsten Pfeiffer <pfeiffer@kde.org>
6 2001 Waldo Bastian <bastian@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24// $Id$
25
26#include "addresslineedit.h"
27
28#include <tqapplication.h>
29#include <tqobject.h>
30#include <tqptrlist.h>
31#include <tqregexp.h>
32#include <tqevent.h>
33#include <tqdragobject.h>
34
35#include <tdecompletionbox.h>
36#include <tdeconfig.h>
37#include <kcursor.h>
38#include <tdestandarddirs.h>
39#include <kstaticdeleter.h>
40#include <tdestdaccel.h>
41#include <kurldrag.h>
42
43#include <tdeabc/stdaddressbook.h>
44#include <tdeabc/distributionlist.h>
45#include "ldapclient.h"
46
47#include <kdebug.h>
48
49//=============================================================================
50//
51// Class AddressLineEdit
52//
53//=============================================================================
54
55
56using namespace TDEABC;
57
58TDECompletion * AddressLineEdit::s_completion = 0L;
59bool AddressLineEdit::s_addressesDirty = false;
60TQTimer* AddressLineEdit::s_LDAPTimer = 0L;
61LdapSearch* AddressLineEdit::s_LDAPSearch = 0L;
62TQString* AddressLineEdit::s_LDAPText = 0L;
63AddressLineEdit* AddressLineEdit::s_LDAPLineEdit = 0L;
64TDEConfig *AddressLineEdit::s_config = 0L;
65
66static KStaticDeleter<TDECompletion> completionDeleter;
67static KStaticDeleter<TQTimer> ldapTimerDeleter;
68static KStaticDeleter<LdapSearch> ldapSearchDeleter;
69static KStaticDeleter<TQString> ldapTextDeleter;
70static KStaticDeleter<TDEConfig> configDeleter;
71
72AddressLineEdit::AddressLineEdit(TQWidget* parent,
73 bool useCompletion,
74 const char *name)
75 : KLineEdit(parent,name)
76{
77 m_useCompletion = useCompletion;
78 m_completionInitialized = false;
79 m_smartPaste = false;
80
81 init();
82
83 // Whenever a new AddressLineEdit is created (== a new composer is created),
84 // we set a dirty flag to reload the addresses upon the first completion.
85 // The address completions are shared between all AddressLineEdits.
86 // Is there a signal that tells us about addressbook updates?
87 if (m_useCompletion)
88 s_addressesDirty = true;
89}
90
91
92//-----------------------------------------------------------------------------
93void AddressLineEdit::init()
94{
95 if ( !s_completion ) {
96 completionDeleter.setObject( s_completion, new TDECompletion() );
97 s_completion->setOrder( TDECompletion::Sorted );
98 s_completion->setIgnoreCase( true );
99 }
100
101 if( m_useCompletion ) {
102 if( !s_LDAPTimer ) {
103 ldapTimerDeleter.setObject( s_LDAPTimer, new TQTimer );
104 ldapSearchDeleter.setObject( s_LDAPSearch, new LdapSearch );
105 ldapTextDeleter.setObject( s_LDAPText, new TQString );
106 }
107 connect( s_LDAPTimer, TQ_SIGNAL( timeout()), TQ_SLOT( slotStartLDAPLookup()));
108 connect( s_LDAPSearch, TQ_SIGNAL( searchData( const TQStringList& )),
109 TQ_SLOT( slotLDAPSearchData( const TQStringList& )));
110 }
111
112 if ( m_useCompletion && !m_completionInitialized )
113 {
114 setCompletionObject( s_completion, false ); // we handle it ourself
115 connect( this, TQ_SIGNAL( completion(const TQString&)),
116 this, TQ_SLOT(slotCompletion() ));
117
118 TDECompletionBox *box = completionBox();
119 connect( box, TQ_SIGNAL( highlighted( const TQString& )),
120 this, TQ_SLOT( slotPopupCompletion( const TQString& ) ));
121 connect( box, TQ_SIGNAL( userCancelled( const TQString& )),
122 TQ_SLOT( userCancelled( const TQString& )));
123
124 m_completionInitialized = true; // don't connect muliple times. That's
125 // ugly, tho, better have completionBox()
126 // virtual in KDE 4
127 // Why? This is only called once. Why should this be called more
128 // than once? And why was this protected?
129 }
130}
131
132//-----------------------------------------------------------------------------
133AddressLineEdit::~AddressLineEdit()
134{
135}
136
137//-----------------------------------------------------------------------------
138
139TDEConfig* AddressLineEdit::config()
140{
141 if ( !s_config )
142 configDeleter.setObject( s_config, new TDEConfig( "kabldaprc", false, false ) ); // Open read-write, no kdeglobals
143
144 return s_config;
145}
146
147void AddressLineEdit::setFont( const TQFont& font )
148{
149 KLineEdit::setFont( font );
150 if ( m_useCompletion )
151 completionBox()->setFont( font );
152}
153
154//-----------------------------------------------------------------------------
155void AddressLineEdit::keyPressEvent(TQKeyEvent *e)
156{
157 bool accept = false;
158
159 if (TDEStdAccel::shortcut(TDEStdAccel::SubstringCompletion).contains(KKey(e)))
160 {
161 doCompletion(true);
162 accept = true;
163 }
164 else if (TDEStdAccel::shortcut(TDEStdAccel::TextCompletion).contains(KKey(e)))
165 {
166 int len = text().length();
167
168 if (len == cursorPosition()) // at End?
169 {
170 doCompletion(true);
171 accept = true;
172 }
173 }
174
175 if( !accept )
176 KLineEdit::keyPressEvent( e );
177
178 if( e->isAccepted())
179 {
180 if( m_useCompletion && s_LDAPTimer != NULL )
181 {
182 if( *s_LDAPText != text())
183 stopLDAPLookup();
184 *s_LDAPText = text();
185 s_LDAPLineEdit = this;
186 s_LDAPTimer->start( 500, true );
187 }
188 }
189}
190
191void AddressLineEdit::mouseReleaseEvent( TQMouseEvent * e )
192{
193 if (m_useCompletion && (e->button() == TQt::MidButton))
194 {
195 m_smartPaste = true;
196 KLineEdit::mouseReleaseEvent(e);
197 m_smartPaste = false;
198 return;
199 }
200 KLineEdit::mouseReleaseEvent(e);
201}
202
203void AddressLineEdit::insert(const TQString &t)
204{
205 if (!m_smartPaste)
206 {
207 KLineEdit::insert(t);
208 return;
209 }
210 TQString newText = t.stripWhiteSpace();
211 if (newText.isEmpty())
212 return;
213
214 // remove newlines in the to-be-pasted string as well as an eventual
215 // mailto: protocol
216 newText.replace( TQRegExp("\r?\n"), ", " );
217 if ( newText.startsWith( "mailto:" ) )
218 {
219 KURL u(newText);
220 newText = u.path();
221 }
222 else if (newText.find(" at ") != -1)
223 {
224 // Anti-spam stuff
225 newText.replace( " at ", "@" );
226 newText.replace( " dot ", "." );
227 }
228 else if (newText.find("(at)") != -1)
229 {
230 newText.replace( TQRegExp("\\s*\\(at\\)\\s*"), "@" );
231 }
232
233 TQString contents = text();
234 int start_sel = 0;
235 int end_sel = 0;
236 int pos = cursorPosition();
237 if (getSelection(&start_sel, &end_sel))
238 {
239 // Cut away the selection.
240 if (pos > end_sel)
241 pos -= (end_sel - start_sel);
242 else if (pos > start_sel)
243 pos = start_sel;
244 contents = contents.left(start_sel) + contents.right(end_sel+1);
245 }
246
247 int eot = contents.length();
248 while ((eot > 0) && contents[eot-1].isSpace()) eot--;
249 if (eot == 0)
250 {
251 contents = TQString::null;
252 }
253 else if (pos >= eot)
254 {
255 if (contents[eot-1] == ',')
256 eot--;
257 contents.truncate(eot);
258 contents += ", ";
259 pos = eot+2;
260 }
261
262 contents = contents.left(pos)+newText+contents.mid(pos);
263 setText(contents);
264 setCursorPosition(pos+newText.length());
265}
266
267void AddressLineEdit::paste()
268{
269 if (m_useCompletion)
270 m_smartPaste = true;
271 KLineEdit::paste();
272 m_smartPaste = false;
273}
274
275//-----------------------------------------------------------------------------
276void AddressLineEdit::cursorAtEnd()
277{
278 setCursorPosition( text().length() );
279}
280
281//-----------------------------------------------------------------------------
282void AddressLineEdit::enableCompletion(bool enable)
283{
284 m_useCompletion = enable;
285}
286
287//-----------------------------------------------------------------------------
288void AddressLineEdit::doCompletion(bool ctrlT)
289{
290 if ( !m_useCompletion )
291 return;
292
293 TQString prevAddr;
294
295 TQString s(text());
296 int n = s.findRev(',');
297
298 if (n >= 0)
299 {
300 n++; // Go past the ","
301
302 int len = s.length();
303
304 // Increment past any whitespace...
305 while( n < len && s[n].isSpace() )
306 n++;
307
308 prevAddr = s.left(n);
309 s = s.mid(n,255).stripWhiteSpace();
310 }
311
312 if ( s_addressesDirty )
313 loadAddresses();
314
315 if ( ctrlT )
316 {
317 TQStringList completions = s_completion->substringCompletion( s );
318 if (completions.count() > 1) {
319 m_previousAddresses = prevAddr;
320 setCompletedItems( completions );
321 }
322 else if (completions.count() == 1)
323 setText(prevAddr + completions.first());
324
325 cursorAtEnd();
326 return;
327 }
328
329 TDEGlobalSettings::Completion mode = completionMode();
330
331 switch ( mode )
332 {
333 case TDEGlobalSettings::CompletionPopupAuto:
334 {
335 if (s.isEmpty())
336 break;
337 }
338 case TDEGlobalSettings::CompletionPopup:
339 {
340 m_previousAddresses = prevAddr;
341 TQStringList items = s_completion->allMatches( s );
342 items += s_completion->allMatches( "\"" + s );
343 items += s_completion->substringCompletion( '<' + s );
344 uint beforeDollarCompletionCount = items.count();
345
346 if( s.find( ' ' ) == -1 ) // one word, possibly given name
347 items += s_completion->allMatches( "$$" + s );
348
349 if ( !items.isEmpty() )
350 {
351 if ( items.count() > beforeDollarCompletionCount )
352 {
353 // remove the '$$whatever$' part
354 for( TQStringList::Iterator it = items.begin();
355 it != items.end();
356 ++it )
357 {
358 int pos = (*it).find( '$', 2 );
359 if( pos < 0 ) // ???
360 continue;
361 (*it)=(*it).mid( pos + 1 );
362 }
363 }
364
365 items = removeMailDupes( items );
366
367 // We do not want KLineEdit::setCompletedItems to perform text
368 // completion (suggestion) since it does not know how to deal
369 // with providing proper completions for different items on the
370 // same line, e.g. comma-separated list of email addresses.
371 bool autoSuggest = (mode != TDEGlobalSettings::CompletionPopupAuto);
372 setCompletedItems( items, autoSuggest );
373
374 if (!autoSuggest)
375 {
376 int index = items.first().find( s );
377 TQString newText = prevAddr + items.first().mid( index );
378 //kdDebug() << "OLD TEXT: " << text() << endl;
379 //kdDebug() << "NEW TEXT: " << newText << endl;
380 setUserSelection(false);
381 setCompletedText(newText,true);
382 }
383 }
384
385 break;
386 }
387
388 case TDEGlobalSettings::CompletionShell:
389 {
390 TQString match = s_completion->makeCompletion( s );
391 if ( !match.isNull() && match != s )
392 {
393 setText( prevAddr + match );
394 cursorAtEnd();
395 }
396 break;
397 }
398
399 case TDEGlobalSettings::CompletionMan: // Short-Auto in fact
400 case TDEGlobalSettings::CompletionAuto:
401 {
402 if (!s.isEmpty())
403 {
404 TQString match = s_completion->makeCompletion( s );
405 if ( !match.isNull() && match != s )
406 {
407 TQString adds = prevAddr + match;
408 setCompletedText( adds );
409 }
410 break;
411 }
412 }
413 case TDEGlobalSettings::CompletionNone:
414 default: // fall through
415 break;
416 }
417}
418
419//-----------------------------------------------------------------------------
420void AddressLineEdit::slotPopupCompletion( const TQString& completion )
421{
422 setText( m_previousAddresses + completion );
423 cursorAtEnd();
424}
425
426//-----------------------------------------------------------------------------
427void AddressLineEdit::loadAddresses()
428{
429 s_completion->clear();
430 s_addressesDirty = false;
431
432 TQStringList adrs = addresses();
433 for( TQStringList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it)
434 addAddress( *it );
435}
436
437void AddressLineEdit::addAddress( const TQString& adr )
438{
439 s_completion->addItem( adr );
440 int pos = adr.find( '<' );
441 if( pos >= 0 )
442 {
443 ++pos;
444 int pos2 = adr.find( pos, '>' );
445 if( pos2 >= 0 )
446 s_completion->addItem( adr.mid( pos, pos2 - pos ));
447 }
448}
449
450void AddressLineEdit::slotStartLDAPLookup()
451{
452 if( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
453 return;
454 startLoadingLDAPEntries();
455}
456
457void AddressLineEdit::stopLDAPLookup()
458{
459 s_LDAPSearch->cancelSearch();
460 s_LDAPLineEdit = NULL;
461}
462
463void AddressLineEdit::startLoadingLDAPEntries()
464{
465 TQString s( *s_LDAPText );
466 // TODO cache last?
467 TQString prevAddr;
468 int n = s.findRev(',');
469 if (n>= 0)
470 {
471 prevAddr = s.left(n+1) + ' ';
472 s = s.mid(n+1,255).stripWhiteSpace();
473 }
474 if( s.length() == 0 )
475 return;
476
477 loadAddresses(); // TODO reuse these?
478 s_LDAPSearch->startSearch( s );
479}
480
481void AddressLineEdit::slotLDAPSearchData( const TQStringList& adrs )
482{
483 if( s_LDAPLineEdit != this )
484 return;
485 for( TQStringList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
486 TQString name(*it);
487 int pos = name.find( " <" );
488 int pos_comma = name.find( ',' );
489 // put name in quotes, if we have a comma in the name
490 if (pos>0 && pos_comma>0 && pos_comma<pos) {
491 name.insert(pos, '\"');
492 name.prepend('\"');
493 }
494 addAddress( name );
495 }
496
497 if( hasFocus() || completionBox()->hasFocus())
498 {
499 if( completionMode() != TDEGlobalSettings::CompletionNone )
500 {
501 doCompletion( false );
502 }
503 }
504}
505
506TQStringList AddressLineEdit::removeMailDupes( const TQStringList& adrs )
507{
508 TQStringList src = adrs;
509 qHeapSort( src );
510 TQString last;
511 for( TQStringList::Iterator it = src.begin(); it != src.end(); ) {
512 if( *it == last )
513 {
514 it = src.remove( it );
515 continue; // dupe
516 }
517 last = *it;
518 ++it;
519 }
520 return src;
521}
522
523//-----------------------------------------------------------------------------
524void AddressLineEdit::dropEvent(TQDropEvent *e)
525{
526 KURL::List uriList;
527 if(KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ))
528 {
529 TQString ct = text();
530 KURL::List::Iterator it = uriList.begin();
531 for (; it != uriList.end(); ++it)
532 {
533 if (!ct.isEmpty()) ct.append(", ");
534 KURL u(*it);
535 if ((*it).protocol() == "mailto")
536 ct.append( (*it).path() );
537 else
538 ct.append( (*it).url() );
539 }
540 setText(ct);
541 setEdited( true );
542 }
543 else {
544 if (m_useCompletion)
545 m_smartPaste = true;
546 TQLineEdit::dropEvent(e);
547 m_smartPaste = false;
548 }
549}
550
551
552TQStringList AddressLineEdit::addresses()
553{
554 TQApplication::setOverrideCursor( KCursor::waitCursor() ); // loading might take a while
555
556 TQStringList result;
557 TQString space(" ");
558 TQRegExp needQuotes("[^ 0-9A-Za-z\\x0080-\\xFFFF]");
559 TQString endQuote("\" ");
560 TQString addr, email;
561
562 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self();
563 TDEABC::AddressBook::Iterator it;
564 for( it = addressBook->begin(); it != addressBook->end(); ++it ) {
565 TQStringList emails = (*it).emails();
566
567 TQString n = (*it).prefix() + space +
568 (*it).givenName() + space +
569 (*it).additionalName() + space +
570 (*it).familyName() + space +
571 (*it).suffix();
572
573 n = n.simplifyWhiteSpace();
574
575 TQStringList::ConstIterator mit;
576
577 for ( mit = emails.begin(); mit != emails.end(); ++mit ) {
578 email = *mit;
579 if (!email.isEmpty()) {
580 if (n.isEmpty() || (email.find( '<' ) != -1))
581 addr = TQString::null;
582 else { /* do we really need quotes around this name ? */
583 if (n.find(needQuotes) != -1)
584 addr = '"' + n + endQuote;
585 else
586 addr = n + space;
587 }
588
589 if (!addr.isEmpty() && (email.find( '<' ) == -1)
590 && (email.find( '>' ) == -1)
591 && (email.find( ',' ) == -1))
592 addr += '<' + email + '>';
593 else
594 addr += email;
595 addr = addr.stripWhiteSpace();
596 result.append( addr );
597 }
598 }
599 }
600
601 TDEABC::DistributionListManager manager( addressBook );
602 manager.load();
603 result += manager.listNames();
604
605 TQApplication::restoreOverrideCursor();
606
607 return result;
608}
609
610#include "addresslineedit.moc"
KCursor::waitCursor
static TQCursor waitCursor()
KKey
KLineEdit
KLineEdit::setCompletedText
virtual void setCompletedText(const TQString &)
KLineEdit::setText
virtual void setText(const TQString &)
KLineEdit::mouseReleaseEvent
virtual void mouseReleaseEvent(TQMouseEvent *)
KLineEdit::completionBox
TDECompletionBox * completionBox(bool create=true)
KLineEdit::setUserSelection
void setUserSelection(bool userSelection)
KLineEdit::setCompletionObject
virtual void setCompletionObject(TDECompletion *, bool hsig=true)
KLineEdit::autoSuggest
bool autoSuggest() const
KLineEdit::completion
void completion(const TQString &)
KLineEdit::userCancelled
void userCancelled(const TQString &cancelText)
KLineEdit::keyPressEvent
virtual void keyPressEvent(TQKeyEvent *)
KLineEdit::setCompletedItems
void setCompletedItems(const TQStringList &items)
KStaticDeleter
KURLDrag::decode
static bool decode(const TQMimeSource *e, KURL::List &urls)
KURL::List
KURL
TDEABC::AddressBook::Iterator
Address Book Iterator.
Definition: addressbook.h:58
TDEABC::AddressBook
Address Book.
Definition: addressbook.h:44
TDEABC::AddressBook::begin
ConstIterator begin() const
Returns an iterator pointing to the first addressee of address book.
Definition: addressbook.cpp:428
TDEABC::AddressBook::end
ConstIterator end() const
Returns an iterator pointing to the last addressee of address book.
Definition: addressbook.cpp:468
TDEABC::AddressLineEdit
A lineedit with LDAP and tdeabc completion.
Definition: addresslineedit.h:51
TDEABC::AddressLineEdit::setFont
virtual void setFont(const TQFont &)
Reimplented for internal reasons.
Definition: addresslineedit.cpp:147
TDEABC::AddressLineEdit::cursorAtEnd
void cursorAtEnd()
Set cursor to end of line.
Definition: addresslineedit.cpp:276
TDEABC::AddressLineEdit::loadAddresses
virtual void loadAddresses()
Always call AddressLineEdit::loadAddresses() as the first thing.
Definition: addresslineedit.cpp:427
TDEABC::AddressLineEdit::enableCompletion
void enableCompletion(bool enable)
Toggle completion.
Definition: addresslineedit.cpp:282
TDEABC::DistributionListManager
Manager of distribution lists.
Definition: distributionlist.h:123
TDEABC::LdapSearch
This class is internal.
Definition: ldapclient.h:208
TDEABC::StdAddressBook::self
static StdAddressBook * self()
Returns the standard addressbook object.
Definition: stdaddressbook.cpp:57
TDECompletionBase::completionMode
TDEGlobalSettings::Completion completionMode() const
TDECompletionBox
TDECompletion
TDECompletion::substringCompletion
TQStringList substringCompletion(const TQString &string) const
TDECompletion::setOrder
virtual void setOrder(CompOrder order)
TDECompletion::allMatches
TQStringList allMatches()
TDECompletion::makeCompletion
virtual TQString makeCompletion(const TQString &string)
TDECompletion::Sorted
Sorted
TDECompletion::setIgnoreCase
virtual void setIgnoreCase(bool ignoreCase)
TDECompletion::clear
virtual void clear()
TDECompletion::addItem
void addItem(const TQString &item)
TDEConfig
TDEGlobalSettings::Completion
Completion
TDEGlobalSettings::CompletionNone
CompletionNone
TDEGlobalSettings::CompletionShell
CompletionShell
TDEGlobalSettings::CompletionAuto
CompletionAuto
TDEGlobalSettings::CompletionPopup
CompletionPopup
TDEGlobalSettings::CompletionMan
CompletionMan
TDEGlobalSettings::CompletionPopupAuto
CompletionPopupAuto
TDEABC
static data, shared by ALL addressee objects
Definition: address.h:48
TDEStdAccel::name
TQString name(StdAccel id)
TDEStdAccel::shortcut
const TDEShortcut & shortcut(StdAccel id)

tdeabc

Skip menu "tdeabc"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeabc

Skip menu "tdeabc"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeabc by doxygen 1.9.4
This website is maintained by Timothy Pearson.