• 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 <kstandarddirs.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 
56 using namespace TDEABC;
57 
58 TDECompletion * AddressLineEdit::s_completion = 0L;
59 bool AddressLineEdit::s_addressesDirty = false;
60 TQTimer* AddressLineEdit::s_LDAPTimer = 0L;
61 LdapSearch* AddressLineEdit::s_LDAPSearch = 0L;
62 TQString* AddressLineEdit::s_LDAPText = 0L;
63 AddressLineEdit* AddressLineEdit::s_LDAPLineEdit = 0L;
64 TDEConfig *AddressLineEdit::s_config = 0L;
65 
66 static KStaticDeleter<TDECompletion> completionDeleter;
67 static KStaticDeleter<TQTimer> ldapTimerDeleter;
68 static KStaticDeleter<LdapSearch> ldapSearchDeleter;
69 static KStaticDeleter<TQString> ldapTextDeleter;
70 static KStaticDeleter<TDEConfig> configDeleter;
71 
72 AddressLineEdit::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 //-----------------------------------------------------------------------------
93 void 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, TQT_SIGNAL( timeout()), TQT_SLOT( slotStartLDAPLookup()));
108  connect( s_LDAPSearch, TQT_SIGNAL( searchData( const TQStringList& )),
109  TQT_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, TQT_SIGNAL( completion(const TQString&)),
116  this, TQT_SLOT(slotCompletion() ));
117 
118  TDECompletionBox *box = completionBox();
119  connect( box, TQT_SIGNAL( highlighted( const TQString& )),
120  this, TQT_SLOT( slotPopupCompletion( const TQString& ) ));
121  connect( box, TQT_SIGNAL( userCancelled( const TQString& )),
122  TQT_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 //-----------------------------------------------------------------------------
133 AddressLineEdit::~AddressLineEdit()
134 {
135 }
136 
137 //-----------------------------------------------------------------------------
138 
139 TDEConfig* 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 
147 void AddressLineEdit::setFont( const TQFont& font )
148 {
149  KLineEdit::setFont( font );
150  if ( m_useCompletion )
151  completionBox()->setFont( font );
152 }
153 
154 //-----------------------------------------------------------------------------
155 void 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 
191 void AddressLineEdit::mouseReleaseEvent( TQMouseEvent * e )
192 {
193  if (m_useCompletion && (e->button() == Qt::MidButton))
194  {
195  m_smartPaste = true;
196  KLineEdit::mouseReleaseEvent(e);
197  m_smartPaste = false;
198  return;
199  }
200  KLineEdit::mouseReleaseEvent(e);
201 }
202 
203 void 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 
267 void AddressLineEdit::paste()
268 {
269  if (m_useCompletion)
270  m_smartPaste = true;
271  KLineEdit::paste();
272  m_smartPaste = false;
273 }
274 
275 //-----------------------------------------------------------------------------
276 void AddressLineEdit::cursorAtEnd()
277 {
278  setCursorPosition( text().length() );
279 }
280 
281 //-----------------------------------------------------------------------------
282 void AddressLineEdit::enableCompletion(bool enable)
283 {
284  m_useCompletion = enable;
285 }
286 
287 //-----------------------------------------------------------------------------
288 void 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 //-----------------------------------------------------------------------------
420 void AddressLineEdit::slotPopupCompletion( const TQString& completion )
421 {
422  setText( m_previousAddresses + completion );
423  cursorAtEnd();
424 }
425 
426 //-----------------------------------------------------------------------------
427 void 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 
437 void 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 
450 void AddressLineEdit::slotStartLDAPLookup()
451 {
452  if( !s_LDAPSearch->isAvailable() || s_LDAPLineEdit != this )
453  return;
454  startLoadingLDAPEntries();
455 }
456 
457 void AddressLineEdit::stopLDAPLookup()
458 {
459  s_LDAPSearch->cancelSearch();
460  s_LDAPLineEdit = NULL;
461 }
462 
463 void 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 
481 void 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 
506 TQStringList 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 //-----------------------------------------------------------------------------
524 void 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 
552 TQStringList 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"
TDEConfig
KURL
TDECompletion::makeCompletion
virtual TQString makeCompletion(const TQString &string)
KLineEdit::keyPressEvent
virtual void keyPressEvent(TQKeyEvent *)
TDECompletion::setIgnoreCase
virtual void setIgnoreCase(bool ignoreCase)
KLineEdit::mouseReleaseEvent
virtual void mouseReleaseEvent(TQMouseEvent *)
TDEABC::AddressLineEdit::enableCompletion
void enableCompletion(bool enable)
Toggle completion.
Definition: addresslineedit.cpp:282
TDEABC::AddressBook
Address Book.
Definition: addressbook.h:43
TDEABC::StdAddressBook::self
static StdAddressBook * self()
Returns the standard addressbook object.
Definition: stdaddressbook.cpp:57
KLineEdit::completion
void completion(const TQString &)
TDECompletion
KStaticDeleter
TDEABC::AddressLineEdit::setFont
virtual void setFont(const TQFont &)
Reimplented for internal reasons.
Definition: addresslineedit.cpp:147
TDECompletionBase::completionMode
TDEGlobalSettings::Completion completionMode() const
TDEGlobalSettings::Completion
Completion
TDEABC::AddressBook::end
ConstIterator end() const
Returns an iterator pointing to the last addressee of address book.
Definition: addressbook.cpp:468
TDEGlobalSettings::CompletionPopup
KLineEdit::autoSuggest
bool autoSuggest() const
TDEStdAccel::shortcut
const TDEShortcut & shortcut(StdAccel id)
TDECompletion::addItem
void addItem(const TQString &item)
KLineEdit::setCompletedItems
void setCompletedItems(const TQStringList &items)
KStaticDeleter::setObject
KDE_DEPRECATED type * setObject(type *obj, bool isArray=false)
TDEGlobalSettings::CompletionPopupAuto
TDEABC
static data, shared by ALL addressee objects
Definition: address.h:48
TDEABC::AddressLineEdit::cursorAtEnd
void cursorAtEnd()
Set cursor to end of line.
Definition: addresslineedit.cpp:276
KCursor::waitCursor
static TQCursor waitCursor()
TDEGlobalSettings::CompletionNone
KLineEdit::setUserSelection
void setUserSelection(bool userSelection)
TDEABC::LdapSearch
This class is internal.
Definition: ldapclient.h:207
KURLDrag::decode
static bool decode(const TQMimeSource *e, KURL::List &urls)
TDEABC::AddressBook::begin
ConstIterator begin() const
Returns an iterator pointing to the first addressee of address book.
Definition: addressbook.cpp:428
TDEABC::AddressLineEdit::loadAddresses
virtual void loadAddresses()
Always call AddressLineEdit::loadAddresses() as the first thing.
Definition: addresslineedit.cpp:427
KLineEdit::setCompletedText
virtual void setCompletedText(const TQString &)
TDECompletion::clear
virtual void clear()
TDECompletion::Sorted
TDEGlobalSettings::CompletionAuto
TDEABC::AddressBook::Iterator
Address Book Iterator.
Definition: addressbook.h:57
TDEABC::AddressLineEdit
A lineedit with LDAP and tdeabc completion.
Definition: addresslineedit.h:50
TDECompletionBox
KLineEdit
KKey
KLineEdit::completionBox
TDECompletionBox * completionBox(bool create=true)
KLineEdit::setCompletionObject
virtual void setCompletionObject(TDECompletion *, bool hsig=true)
TDEABC::DistributionListManager
Manager of distribution lists.
Definition: distributionlist.h:122
TDEGlobalSettings::CompletionMan
KLineEdit::userCancelled
void userCancelled(const TQString &cancelText)
TDECompletion::setOrder
virtual void setOrder(CompOrder order)
TDECompletion::substringCompletion
TQStringList substringCompletion(const TQString &string) const
KURL::List
TDECompletion::allMatches
TQStringList allMatches()
TDEGlobalSettings::CompletionShell
KLineEdit::setText
virtual void setText(const TQString &)

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeabc by doxygen 1.8.8
This website is maintained by Timothy Pearson.