• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

kabc

  • sources
  • kde-4.12
  • kdepimlibs
  • kabc
addresslineedit.cpp
1 /*
2  This file is part of libkabc.
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 #include "addresslineedit.h"
25 
26 #include <QApplication>
27 #include <QKeyEvent>
28 #include <QMouseEvent>
29 #include <QtCore/QObject>
30 #include <QtCore/QRegExp>
31 
32 #include <kcompletionbox.h>
33 #include <kconfig.h>
34 #include <kcursor.h>
35 #include <kdebug.h>
36 #include <kstandarddirs.h>
37 #include <kstandardshortcut.h>
38 
39 #include "stdaddressbook.h"
40 
41 //=============================================================================
42 //
43 // Class AddressLineEdit
44 //
45 //=============================================================================
46 
47 using namespace KABC;
48 
49 class AddressLineEdit::Private
50 {
51  public:
52  Private( AddressLineEdit *parent )
53  : mParent( parent ),
54  mCompletionInitialized( false ),
55  mSmartPaste( false )
56  {
57  init();
58  }
59 
60  void init();
61  QStringList addresses();
62  QStringList removeMailDupes( const QStringList &adrs );
63 
64  void slotCompletion() { mParent->doCompletion( false ); }
65  void slotPopupCompletion( const QString &completion );
66 
67  AddressLineEdit *mParent;
68  QString mPreviousAddresses;
69  bool mUseCompletion;
70  bool mCompletionInitialized;
71  bool mSmartPaste;
72 
73  static bool sAddressesDirty;
74  static bool initialized;
75 };
76 bool AddressLineEdit::Private::initialized = false;
77 K_GLOBAL_STATIC( KCompletion, sCompletion )
78 
79 void AddressLineEdit::Private::init()
80 {
81  if ( !Private::initialized ) {
82  Private::initialized = true;
83  sCompletion->setOrder( KCompletion::Sorted );
84  sCompletion->setIgnoreCase( true );
85  }
86 
87  if ( mUseCompletion && !mCompletionInitialized ) {
88  mParent->setCompletionObject( sCompletion, false ); // we handle it ourself
89  mParent->connect( mParent, SIGNAL(completion(QString)),
90  mParent, SLOT(slotCompletion()) );
91 
92  KCompletionBox *box = mParent->completionBox();
93  mParent->connect( box, SIGNAL(currentTextChanged(QString)),
94  mParent, SLOT(slotPopupCompletion(QString)) );
95  mParent->connect( box, SIGNAL(userCancelled(QString)),
96  SLOT(userCancelled(QString)) );
97 
98  mCompletionInitialized = true; // don't connect muliple times. That's
99  // ugly, tho, better have completionBox()
100  // virtual in KDE 4
101  // Why? This is only called once. Why should this be called more
102  // than once? And why was this protected?
103  }
104 }
105 
106 QStringList AddressLineEdit::Private::addresses()
107 {
108  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) ); // loading might take a while
109 
110  QStringList result;
111  QLatin1String space( " " );
112  QRegExp needQuotes( QLatin1String( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) );
113  QLatin1String endQuote( "\" " );
114  QString addr, email;
115 
116  KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
117  KABC::AddressBook::Iterator it;
118  for ( it = addressBook->begin(); it != addressBook->end(); ++it ) {
119  QStringList emails = ( *it ).emails();
120 
121  QString n = ( *it ).prefix() + space +
122  ( *it ).givenName() + space +
123  ( *it ).additionalName() + space +
124  ( *it ).familyName() + space +
125  ( *it ).suffix();
126 
127  n = n.simplified();
128 
129  QStringList::ConstIterator mit;
130  QStringList::ConstIterator end( emails.constEnd() );
131 
132  for ( mit = emails.constBegin(); mit != end; ++mit ) {
133  email = *mit;
134  if ( !email.isEmpty() ) {
135  if ( n.isEmpty() || ( email.indexOf( QLatin1Char( '<' ) ) != -1 ) ) {
136  addr.clear();
137  } else { /* do we really need quotes around this name ? */
138  if ( n.indexOf( needQuotes ) != -1 ) {
139  addr = QLatin1Char( '"' ) + n + endQuote;
140  } else {
141  addr = n + space;
142  }
143  }
144 
145  if ( !addr.isEmpty() &&
146  ( email.indexOf( QLatin1Char( '<' ) ) == -1 ) &&
147  ( email.indexOf( QLatin1Char( '>' ) ) == -1 ) &&
148  ( email.indexOf( QLatin1Char( ',' ) ) == -1 ) ) {
149  addr += QLatin1Char( '<' ) + email + QLatin1Char( '>' );
150  } else {
151  addr += email;
152  }
153  addr = addr.trimmed();
154  result.append( addr );
155  }
156  }
157  }
158 
159  result += addressBook->allDistributionListNames();
160 
161  QApplication::restoreOverrideCursor();
162 
163  return result;
164 }
165 
166 QStringList AddressLineEdit::Private::removeMailDupes( const QStringList &addrs )
167 {
168  QStringList src( addrs );
169  qSort( src );
170 
171  QString last;
172  for ( QStringList::Iterator it = src.begin(); it != src.end(); ) {
173  if ( *it == last ) {
174  it = src.erase( it );
175  continue; // dupe
176  }
177 
178  last = *it;
179  ++it;
180  }
181 
182  return src;
183 }
184 
185 void AddressLineEdit::Private::slotPopupCompletion( const QString &completion )
186 {
187  mParent->setText( mPreviousAddresses + completion );
188  mParent->cursorAtEnd();
189 }
190 
191 bool AddressLineEdit::Private::sAddressesDirty = false;
192 
193 AddressLineEdit::AddressLineEdit( QWidget *parent, bool useCompletion )
194  : KLineEdit( parent ), d( new Private( this ) )
195 {
196  d->mUseCompletion = useCompletion;
197 
198  // Whenever a new AddressLineEdit is created (== a new composer is created),
199  // we set a dirty flag to reload the addresses upon the first completion.
200  // The address completions are shared between all AddressLineEdits.
201  // Is there a signal that tells us about addressbook updates?
202  if ( d->mUseCompletion ) {
203  d->sAddressesDirty = true;
204  }
205 }
206 
207 //-----------------------------------------------------------------------------
208 AddressLineEdit::~AddressLineEdit()
209 {
210  delete d;
211 }
212 
213 //-----------------------------------------------------------------------------
214 
215 void AddressLineEdit::setFont( const QFont &font )
216 {
217  KLineEdit::setFont( font );
218  if ( d->mUseCompletion ) {
219  completionBox()->setFont( font );
220  }
221 }
222 
223 //-----------------------------------------------------------------------------
224 void AddressLineEdit::keyPressEvent( QKeyEvent *event )
225 {
226  bool accept = false;
227 
228  if ( KStandardShortcut::shortcut( KStandardShortcut::SubstringCompletion ).
229  contains( event->key() | event->modifiers() ) ) {
230  doCompletion( true );
231  accept = true;
232  } else if ( KStandardShortcut::shortcut( KStandardShortcut::TextCompletion ).
233  contains( event->key() | event->modifiers() ) ) {
234  int len = text().length();
235 
236  if ( len == cursorPosition() ) { // at End?
237  doCompletion( true );
238  accept = true;
239  }
240  }
241 
242  if ( !accept ) {
243  KLineEdit::keyPressEvent( event );
244  }
245 }
246 
247 void AddressLineEdit::mouseReleaseEvent( QMouseEvent *event )
248 {
249  if ( d->mUseCompletion && ( event->button() == Qt::MidButton ) ) {
250  d->mSmartPaste = true;
251  KLineEdit::mouseReleaseEvent( event );
252  d->mSmartPaste = false;
253  return;
254  }
255 
256  KLineEdit::mouseReleaseEvent( event );
257 }
258 
259 void AddressLineEdit::insert( const QString &oldText )
260 {
261  if ( !d->mSmartPaste ) {
262  KLineEdit::insert( oldText );
263  return;
264  }
265 
266  QString newText = oldText.trimmed();
267  if ( newText.isEmpty() ) {
268  return;
269  }
270 
271  // remove newlines in the to-be-pasted string as well as an eventual
272  // mailto: protocol
273  newText.replace( QRegExp( QLatin1String( "\r?\n" ) ), QLatin1String( ", " ) );
274  if ( newText.startsWith( QLatin1String( "mailto:" ) ) ) {
275  KUrl u( newText );
276  newText = u.path();
277  } else if ( newText.indexOf( QLatin1String( " at " ) ) != -1 ) {
278  // Anti-spam stuff
279  newText.replace( QLatin1String( " at " ), QLatin1String( "@" ) );
280  newText.replace( QLatin1String( " dot " ), QLatin1String( "." ) );
281  } else if ( newText.indexOf( QLatin1String( "(at)" ) ) != -1 ) {
282  newText.replace( QRegExp( QLatin1String( "\\s*\\(at\\)\\s*" ) ), QLatin1String( "@" ) );
283  }
284 
285  QString contents = text();
286  int start_sel = 0;
287  int end_sel = 0;
288  int pos = cursorPosition();
289  if ( !selectedText().isEmpty() ) {
290  // Cut away the selection.
291  if ( pos > end_sel ) {
292  pos -= ( end_sel - start_sel );
293  } else if ( pos > start_sel ) {
294  pos = start_sel;
295  }
296  contents = contents.left( start_sel ) + contents.right( end_sel + 1 );
297  }
298 
299  int eot = contents.length();
300  while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() ) {
301  eot--;
302  }
303 
304  if ( eot == 0 ) {
305  contents.clear();
306  } else if ( pos >= eot ) {
307  if ( contents[ eot - 1 ] == QLatin1Char( ',' ) ) {
308  eot--;
309  }
310  contents.truncate( eot );
311  contents += QLatin1String( ", " );
312  pos = eot+2;
313  }
314 
315  contents = contents.left( pos ) + newText + contents.mid( pos );
316  setText( contents );
317  setCursorPosition( pos + newText.length() );
318 }
319 
320 void AddressLineEdit::paste()
321 {
322  if ( d->mUseCompletion ) {
323  d->mSmartPaste = true;
324  }
325 
326  KLineEdit::paste();
327  d->mSmartPaste = false;
328 }
329 
330 //-----------------------------------------------------------------------------
331 void AddressLineEdit::cursorAtEnd()
332 {
333  setCursorPosition( text().length() );
334 }
335 
336 //-----------------------------------------------------------------------------
337 void AddressLineEdit::enableCompletion( bool enable )
338 {
339  d->mUseCompletion = enable;
340 }
341 
342 //-----------------------------------------------------------------------------
343 void AddressLineEdit::doCompletion( bool ctrlT )
344 {
345  if ( !d->mUseCompletion ) {
346  return;
347  }
348 
349  QString prevAddr;
350 
351  QString s( text() );
352  int n = s.lastIndexOf( QLatin1Char( ',' ) );
353 
354  if ( n >= 0 ) {
355  n++; // Go past the ","
356 
357  int len = s.length();
358 
359  // Increment past any whitespace...
360  while ( n < len && s[ n ].isSpace() ) {
361  n++;
362  }
363 
364  prevAddr = s.left( n );
365  s = s.mid( n, 255 ).trimmed();
366  }
367 
368  if ( d->sAddressesDirty ) {
369  loadAddresses();
370  }
371 
372  if ( ctrlT ) {
373  QStringList completions = sCompletion->substringCompletion( s );
374  if ( completions.count() > 1 ) {
375  d->mPreviousAddresses = prevAddr;
376  setCompletedItems( completions );
377  } else if ( completions.count() == 1 ) {
378  setText( prevAddr + completions.first() );
379  }
380 
381  cursorAtEnd();
382  return;
383  }
384 
385  KGlobalSettings::Completion mode = completionMode();
386 
387  switch ( mode ) {
388  case KGlobalSettings::CompletionPopupAuto:
389  {
390  if ( s.isEmpty() ) {
391  break;
392  }
393  }
394  case KGlobalSettings::CompletionPopup:
395  {
396  d->mPreviousAddresses = prevAddr;
397  QStringList items = sCompletion->allMatches( s );
398  items += sCompletion->allMatches( QLatin1String( "\"" ) + s );
399  items += sCompletion->substringCompletion( QLatin1Char( '<' ) + s );
400  int beforeDollarCompletionCount = items.count();
401 
402  if ( s.indexOf( QLatin1Char( ' ' ) ) == -1 ) { // one word, possibly given name
403  items += sCompletion->allMatches( QLatin1String( "$$" ) + s );
404  }
405 
406  if ( !items.isEmpty() ) {
407  if ( items.count() > beforeDollarCompletionCount ) {
408  // remove the '$$whatever$' part
409  for ( QStringList::Iterator it = items.begin();
410  it != items.end(); ++it ) {
411  int pos = ( *it ).indexOf( QLatin1Char( '$' ), 2 );
412  if ( pos < 0 ) { // ???
413  continue;
414  }
415  ( *it ) = ( *it ).mid( pos + 1 );
416  }
417  }
418 
419  items = d->removeMailDupes( items );
420 
421  // We do not want KLineEdit::setCompletedItems to perform text
422  // completion (suggestion) since it does not know how to deal
423  // with providing proper completions for different items on the
424  // same line, e.g. comma-separated list of email addresses.
425  bool autoSuggest = ( mode != KGlobalSettings::CompletionPopupAuto );
426  setCompletedItems( items, autoSuggest );
427 
428  if ( !autoSuggest ) {
429  int index = items.first().indexOf( s );
430  QString newText = prevAddr + items.first().mid( index );
431  //kDebug() << "OLD TEXT:" << text();
432  //kDebug() << "NEW TEXT:" << newText;
433  setUserSelection( false );
434  setCompletedText( newText, true );
435  }
436  }
437 
438  break;
439  }
440 
441  case KGlobalSettings::CompletionShell:
442  {
443  QString match = sCompletion->makeCompletion( s );
444  if ( !match.isNull() && match != s ) {
445  setText( prevAddr + match );
446  cursorAtEnd();
447  }
448  break;
449  }
450 
451  case KGlobalSettings::CompletionMan: // Short-Auto in fact
452  case KGlobalSettings::CompletionAuto:
453  {
454  if ( !s.isEmpty() ) {
455  QString match = sCompletion->makeCompletion( s );
456  if ( !match.isNull() && match != s ) {
457  setCompletedText( prevAddr + match );
458  }
459 
460  break;
461  }
462  }
463  case KGlobalSettings::CompletionNone:
464  default: // fall through
465  break;
466  }
467 }
468 
469 //-----------------------------------------------------------------------------
470 void AddressLineEdit::loadAddresses()
471 {
472  sCompletion->clear();
473  d->sAddressesDirty = false;
474 
475  const QStringList addrs = d->addresses();
476  QStringList::ConstIterator end( addrs.end() );
477  for ( QStringList::ConstIterator it = addrs.begin(); it != end; ++it ) {
478  addAddress( *it );
479  }
480 }
481 
482 void AddressLineEdit::addAddress( const QString &addr )
483 {
484  sCompletion->addItem( addr );
485 
486  int pos = addr.indexOf( QLatin1Char( '<' ) );
487  if ( pos >= 0 ) {
488  ++pos;
489  int pos2 = addr.indexOf( QLatin1Char( '>' ), pos );
490  if ( pos2 >= 0 ) {
491  sCompletion->addItem( addr.mid( pos, pos2 - pos ) );
492  }
493  }
494 }
495 
496 //-----------------------------------------------------------------------------
497 void AddressLineEdit::dropEvent( QDropEvent *event )
498 {
499  const KUrl::List uriList = KUrl::List::fromMimeData( event->mimeData() );
500  if ( !uriList.isEmpty() ) {
501  QString ct = text();
502  KUrl::List::ConstIterator it = uriList.begin();
503  for ( ; it != uriList.end(); ++it ) {
504  if ( !ct.isEmpty() ) {
505  ct.append( QLatin1String( ", " ) );
506  }
507 
508  KUrl u( *it );
509  if ( ( *it ).protocol() == QLatin1String( "mailto" ) ) {
510  ct.append( ( *it ).path() );
511  } else {
512  ct.append( ( *it ).url() );
513  }
514  }
515  setText( ct );
516  setModified( true );
517  } else {
518  if ( d->mUseCompletion ) {
519  d->mSmartPaste = true;
520  }
521 
522  KLineEdit::dropEvent( event );
523  d->mSmartPaste = false;
524  }
525 }
526 
527 #include "moc_addresslineedit.cpp"
KABC::AddressBook::end
ConstIterator end() const
Returns an iterator pointing to the last addressee of address book.
Definition: addressbook.cpp:491
KABC::AddressLineEdit::doCompletion
void doCompletion(bool)
Triggers looking for a completion of the address or the last address if there are already more than o...
Definition: addresslineedit.cpp:343
KABC::AddressLineEdit::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *e)
Enables smart paste for X11 middle mouse text paste if completion is enabled.
Definition: addresslineedit.cpp:247
KABC::AddressLineEdit::addAddress
void addAddress(const QString &addr)
Adds a new address to the line edit.
Definition: addresslineedit.cpp:482
KABC::AddressBook::allDistributionListNames
QStringList allDistributionListNames() const
Returns a list of names of all distribution lists of all resources of this address book...
Definition: addressbook.cpp:731
KABC::AddressLineEdit::loadAddresses
virtual void loadAddresses()
Always call AddressLineEdit::loadAddresses() as the first thing.
Definition: addresslineedit.cpp:470
KABC::AddressLineEdit::paste
virtual void paste()
Pastes the clipboard content.
Definition: addresslineedit.cpp:320
KABC::AddressLineEdit::~AddressLineEdit
virtual ~AddressLineEdit()
Destroys the instance.
Definition: addresslineedit.cpp:208
KABC::AddressBook::begin
ConstIterator begin() const
Returns an iterator pointing to the first addressee of address book.
Definition: addressbook.cpp:446
KABC::AddressLineEdit
A lineedit with kabc completion.
Definition: addresslineedit.h:43
KABC::AddressLineEdit::AddressLineEdit
AddressLineEdit(QWidget *parent, bool useCompletion=true)
Creates the line edit instance.
Definition: addresslineedit.cpp:193
KABC::AddressLineEdit::cursorAtEnd
void cursorAtEnd()
Set cursor to end of line.
Definition: addresslineedit.cpp:331
KABC::AddressLineEdit::keyPressEvent
virtual void keyPressEvent(QKeyEvent *e)
Handles KDE completion short cuts.
Definition: addresslineedit.cpp:224
KABC::AddressLineEdit::setFont
virtual void setFont(const QFont &font)
Reimplemented for internal reasons.
Definition: addresslineedit.cpp:215
KABC::AddressLineEdit::dropEvent
virtual void dropEvent(QDropEvent *e)
Handles drop events.
Definition: addresslineedit.cpp:497
KABC::StdAddressBook::self
static StdAddressBook * self()
Returns the standard addressbook object.
Definition: stdaddressbook.cpp:74
KABC::AddressBook::Iterator
Address Book Iterator.
Definition: addressbook.h:64
KABC::AddressBook
Address Book.
Definition: addressbook.h:46
KABC::AddressLineEdit::insert
virtual void insert(const QString &addr)
Inserts the given string.
Definition: addresslineedit.cpp:259
KABC::AddressLineEdit::enableCompletion
void enableCompletion(bool enable)
Toggle completion.
Definition: addresslineedit.cpp:337
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:01:05 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kabc

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

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal