kaddressbook

imeditorwidget.cpp
1 /*
2  IM address editor widget for KAddressBook
3 
4  Copyright (c) 2004 Will Stephenson <lists@stevello.free-online.co.uk>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20  As a special exception, permission is given to link this program
21  with any edition of TQt, and distribute the resulting executable,
22  without including the source code for TQt in the source distribution.
23 */
24 
25 #include <tqlistview.h>
26 #include <tqstringlist.h>
27 #include <tqvbox.h>
28 #include <tqlayout.h>
29 #include <tqfont.h>
30 #include <tqpainter.h>
31 
32 #include <kdialogbase.h>
33 #include <kdebug.h>
34 #include <kiconloader.h>
35 #include <tdelocale.h>
36 #include <tdemessagebox.h>
37 #include <kplugininfo.h>
38 #include <kpushbutton.h>
39 #include <ktrader.h>
40 
41 #include "imaddresswidget.h"
42 #include "imeditorbase.h"
43 #include "imeditorwidget.h"
44 
45 
46 IMAddressLVI::IMAddressLVI( TDEListView *parent, KPluginInfo *protocol,
47  const TQString &address, const IMContext &context )
48  : TDEListViewItem( parent )
49 {
50  setProtocol( protocol );
51  setAddress( address );
52  setContext( context );
53  mPreferred = false;
54 }
55 
56 void IMAddressLVI::setPreferred( bool preferred )
57 {
58  mPreferred = preferred;
59 }
60 
61 bool IMAddressLVI::preferred() const
62 {
63  return mPreferred;
64 }
65 
66 void IMAddressLVI::paintCell( TQPainter *p, const TQColorGroup &cg,
67  int column, int width, int alignment )
68 {
69  if ( mPreferred ) {
70  TQFont font = p->font();
71  font.setBold( true );
72  p->setFont( font );
73  }
74 
75  TDEListViewItem::paintCell( p, cg, column, width, alignment );
76 }
77 
78 void IMAddressLVI::setAddress( const TQString &address )
79 {
80  // irc uses 0xE120 to seperate the nick and the server group.
81  TQString serverOrGroup = address.section( TQChar( 0xE120 ), 1 );
82 
83  if ( serverOrGroup.isEmpty() )
84  setText( 1, address );
85  else {
86  TQString nickname = address.section( TQChar( 0xE120 ), 0, 0 );
87  setText( 1, i18n( "<nickname> on <server>","%1 on %2" )
88  .arg( nickname ).arg( serverOrGroup ) );
89  }
90 
91  mAddress = address;
92 }
93 
94 void IMAddressLVI::setContext( const IMContext &context )
95 {
96  mContext = context;
97  // set context
98 /* switch ( context )
99  {
100  case Home:
101  setText( 2, i18n( "Home" ) );
102  break;
103  case Work:
104  setText( 2, i18n( "Work" ) );
105  break;
106  case Any:
107  setText( 2, i18n( "Any" ) );
108  break;
109  }
110 */
111 }
112 
113 void IMAddressLVI::setProtocol( KPluginInfo *protocol )
114 {
115  mProtocol = protocol;
116 
117  setPixmap( 0, SmallIcon( mProtocol->icon() ) );
118  setText( 0, mProtocol->name() );
119 }
120 
121 KPluginInfo * IMAddressLVI::protocol() const
122 {
123  return mProtocol;
124 }
125 
126 IMContext IMAddressLVI::context() const
127 {
128  return mContext;
129 }
130 
131 TQString IMAddressLVI::address() const
132 {
133  return mAddress;
134 }
135 
136 void IMAddressLVI::activate()
137 {
138  // show editor
139 }
140 
141 /*===========================================================================*/
142 
143 IMEditorWidget::IMEditorWidget( TQWidget *parent, const TQString &preferredIM, const char *name )
144  : KDialogBase( parent, name, false, i18n( "Edit Instant Messenging Address" ),
145  Help | Ok | Cancel, Ok, false ),
146  mReadOnly( false )
147 {
148  mWidget = new IMEditorBase( this );
149  setMainWidget( mWidget );
150 
151  connect( mWidget->btnAdd, TQ_SIGNAL( clicked() ), TQ_SLOT( slotAdd() ) );
152  connect( mWidget->btnEdit, TQ_SIGNAL( clicked() ), TQ_SLOT( slotEdit() ) );
153  connect( mWidget->btnDelete, TQ_SIGNAL( clicked() ), TQ_SLOT( slotDelete() ) );
154  connect( mWidget->btnSetStandard, TQ_SIGNAL( clicked()), TQ_SLOT( slotSetStandard() ) );
155  connect( mWidget->lvAddresses, TQ_SIGNAL( selectionChanged() ), TQ_SLOT( slotUpdateButtons() ) );
156 
157  connect( mWidget->lvAddresses, TQ_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint&, int ) ),
158  TQ_SLOT( slotEdit() ) );
159 
160  setHelp( "managing-contacts-im-addresses" );
161 
162  mWidget->btnEdit->setEnabled( false );
163  mWidget->btnDelete->setEnabled( false );
164  mWidget->btnSetStandard->setEnabled( false );
165  // Disabled pending implementation
166  //mWidget->btnUp->setEnabled( false );
167  //mWidget->btnDown->setEnabled( false );
168  mPreferred = preferredIM;
169  mPreferred = mPreferred.replace( " on ", TQString( TQChar( 0xE120 ) ), true );
170  mProtocols = KPluginInfo::fromServices( TDETrader::self()->query( TQString::fromLatin1( "KABC/IMProtocol" ) ) );
171 
172  // order the protocols by putting them in a qmap, then sorting the set of keys and recreating the list
173  TQMap<TQString, KPluginInfo *> protocolMap;
174  TQValueList<KPluginInfo *>::ConstIterator it;
175  TQValueList<KPluginInfo *> sorted;
176  for ( it = mProtocols.begin(); it != mProtocols.end(); ++it )
177  protocolMap.insert( (*it)->name(), (*it) );
178 
179  TQStringList keys = protocolMap.keys();
180  keys.sort();
181  TQStringList::ConstIterator keyIt = keys.begin();
182  TQStringList::ConstIterator end = keys.end();
183  for ( ; keyIt != end; ++keyIt )
184  sorted.append( protocolMap[*keyIt] );
185  mProtocols = sorted;
186 }
187 
188 TQValueList<KPluginInfo *> IMEditorWidget::availableProtocols() const
189 {
190  return mProtocols;
191 }
192 
193 void IMEditorWidget::loadContact( TDEABC::Addressee *addr )
194 {
195  if ( mWidget->lvAddresses )
196  mWidget->lvAddresses->clear();
197 
198  // see README for details of how Evolution stores IM addresses (differently)
199  const TQStringList customs = addr->customs();
200 
201  TQStringList::ConstIterator it;
202  bool isSet = false;
203  for ( it = customs.begin(); it != customs.end(); ++it ) {
204  TQString app, name, value;
205  splitField( *it, app, name, value );
206 
207  if ( app.startsWith( TQString::fromLatin1( "messaging/" ) ) ) {
208  if ( name == TQString::fromLatin1( "All" ) ) {
209  KPluginInfo *protocol = protocolFromString( app );
210  if ( protocol ) {
211  TQStringList addresses = TQStringList::split( TQChar( 0xE000 ), value );
212  TQStringList::iterator end = addresses.end();
213  for ( TQStringList::ConstIterator it = addresses.begin(); it != end; ++it ) {
214  IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, protocol, *it, Any/*, false*/ );
215  if ( !isSet && (*it).stripWhiteSpace().lower() == mPreferred.stripWhiteSpace().lower() ) {
216  imaddresslvi->setPreferred( true );
217  isSet = true; //Only set one item to be preferred
218  }
219  }
220  } else
221  kdDebug( 5720 ) << k_funcinfo << " no protocol found for: " << app << endl;
222  }
223  }
224  }
225 
226  if ( mWidget->lvAddresses->firstChild() )
227  mWidget->lvAddresses->firstChild()->setSelected( true );
228 }
229 
230 void IMEditorWidget::storeContact( TDEABC::Addressee *addr )
231 {
232  // for each changed protocol, write a new custom field containing the current set of
233  // addresses
234  TQValueList<KPluginInfo *>::ConstIterator protocolIt;
235  for ( protocolIt = mChangedProtocols.begin(); protocolIt != mChangedProtocols.end(); ++protocolIt ) {
236  TQStringList lst;
237  TQListViewItemIterator addressIt( mWidget->lvAddresses );
238  while ( addressIt.current() ) {
239  IMAddressLVI* currentAddress = static_cast<IMAddressLVI*>( *addressIt );
240  if ( currentAddress->protocol() == *protocolIt )
241  lst.append( currentAddress->address() );
242  ++addressIt;
243  }
244 
245  TQString addrBookField = (*protocolIt)->property( "X-TDE-InstantMessagingKABCField" ).toString();
246  if ( !lst.isEmpty() )
247  addr->insertCustom( addrBookField, TQString::fromLatin1( "All" ), lst.join( TQChar( 0xE000 ) ) );
248  else
249  addr->removeCustom( addrBookField, TQString::fromLatin1( "All" ) );
250  }
251 }
252 
253 void IMEditorWidget::setReadOnly( bool readOnly )
254 {
255  mReadOnly = readOnly;
256  slotUpdateButtons();
257 }
258 
259 void IMEditorWidget::slotSetStandard()
260 {
261  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
262 
263  // Just set the first one selected as standard
264  if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
265  TQListViewItemIterator it2( mWidget->lvAddresses );
266  while ( it2.current() ) {
267  IMAddressLVI *item = static_cast<IMAddressLVI*>( it2.current() );
268 
269  if ( item->preferred() ) {
270  if ( current == item )
271  return; //Selected is already preferred
272  else {
273  item->setPreferred( false );
274  mWidget->lvAddresses->repaintItem( item );
275  break;
276  }
277  }
278 
279  ++it2;
280  }
281 
282  mPreferred = current->address();
283  current->setPreferred( true );
284  setModified( true );
285  mWidget->lvAddresses->repaintItem( current );
286  }
287 }
288 
289 void IMEditorWidget::slotUpdateButtons()
290 {
291  int num_selected = 0;
292  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
293  while ( it.current() ) {
294  ++num_selected;
295  if ( num_selected > 1 )
296  break; //no need to count above 2.
297 
298  ++it;
299  }
300 
301  if ( !mReadOnly && num_selected == 1 ) {
302  mWidget->btnAdd->setEnabled( true );
303  mWidget->btnEdit->setEnabled( true );
304  mWidget->btnDelete->setEnabled( true );
305  IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() );
306 
307  // Disable "set standard" if already standard
308  mWidget->btnSetStandard->setEnabled( !current || !current->preferred() );
309  } else if ( !mReadOnly && num_selected > 1 ) {
310  mWidget->btnAdd->setEnabled( true );
311  mWidget->btnEdit->setEnabled( false );
312  mWidget->btnDelete->setEnabled( true );
313  mWidget->btnSetStandard->setEnabled( false );
314  } else {
315  mWidget->btnAdd->setEnabled( !mReadOnly );
316  mWidget->btnSetStandard->setEnabled( false );
317  mWidget->btnEdit->setEnabled( false );
318  mWidget->btnDelete->setEnabled( false );
319  }
320 }
321 
322 void IMEditorWidget::setModified( bool modified )
323 {
324  mModified = modified;
325 }
326 
327 bool IMEditorWidget::isModified() const
328 {
329  return mModified;
330 }
331 
332 void IMEditorWidget::slotAdd()
333 {
334  KDialogBase addDialog( this, "addaddress", true, i18n( "Instant messaging", "Add Address" ),
335  KDialogBase::Ok | KDialogBase::Cancel );
336 
337  IMAddressWidget *addressWid = new IMAddressWidget( &addDialog, mProtocols );
338  addDialog.enableButtonOK( false );
339  connect( addressWid, TQ_SIGNAL( inValidState( bool ) ),
340  &addDialog, TQ_SLOT( enableButtonOK( bool ) ) );
341  addDialog.setMainWidget( addressWid );
342 
343  if ( addDialog.exec() == TQDialog::Accepted ) {
344  // add the new item
345  IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, addressWid->protocol(),
346  addressWid->address() /*, addressWid->context() */ );
347 
348  // If it's a new address, set is as preferred.
349  if ( mPreferred.isEmpty() ) {
350  imaddresslvi->setPreferred( true );
351  mPreferred = addressWid->address();
352  }
353 
354  if ( mChangedProtocols.find( addressWid->protocol() ) == mChangedProtocols.end() )
355  mChangedProtocols.append( addressWid->protocol() );
356 
357  mWidget->lvAddresses->sort();
358 
359  setModified( true );
360  }
361 }
362 
363 void IMEditorWidget::slotEdit()
364 {
365  if( mReadOnly )
366  return;
367  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
368 
369  // Just edit the first one selected.
370  if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
371  KDialogBase editDialog( this, "editaddress", true, i18n( "Instant messaging", "Edit Address" ),
372  KDialogBase::Ok | KDialogBase::Cancel );
373  IMAddressWidget *addressWid = new IMAddressWidget( &editDialog, mProtocols, current->protocol(),
374  current->address(), current->context() ) ;
375  connect( addressWid, TQ_SIGNAL( inValidState( bool ) ),
376  &editDialog, TQ_SLOT( enableButtonOK( bool ) ) );
377  editDialog.setMainWidget( addressWid );
378 
379  if ( editDialog.exec() == TQDialog::Accepted ) {
380  bool modified = false;
381  if ( addressWid->address() != current->address() ) {
382  modified = true;
383  current->setAddress( addressWid->address() );
384  }
385  if ( addressWid->context() != current->context() ) {
386  modified = true;
387  current->setContext( addressWid->context() );
388  }
389 
390  // the entry for the protocol of the current address has changed
391  if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) {
392  mChangedProtocols.append( current->protocol() );
393  }
394  // update protocol - has another protocol gained an address?
395  if ( current->protocol() != addressWid->protocol() ) {
396  modified = true;
397  // this proto is losing an entry
398  current->setProtocol( addressWid->protocol() );
399  if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
400  mChangedProtocols.append( current->protocol() );
401  }
402 
403  if ( modified )
404  setModified(true);
405  }
406  }
407 }
408 
409 void IMEditorWidget::slotDelete()
410 {
411  int num_selected = 0;
412 
413  {
414  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
415  while ( it.current() ) {
416  num_selected++;
417  ++it;
418  }
419  }
420 
421  if ( num_selected == 0 )
422  return;
423 
424  if ( KMessageBox::warningContinueCancel( this, i18n( "Do you really want to delete the selected address?",
425  "Do you really want to delete the %n selected addresses?", num_selected ),
426  i18n( "Confirm Delete" ), KStdGuiItem::del() ) != KMessageBox::Continue )
427  return;
428 
429  TQListViewItemIterator it( mWidget->lvAddresses );
430  bool deletedPreferred = false;
431  while( it.current() ) {
432  if ( it.current()->isSelected() ) {
433  IMAddressLVI * current = static_cast<IMAddressLVI*>( *it );
434  if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
435  mChangedProtocols.append( current->protocol() );
436 
437  if ( current->preferred() )
438  deletedPreferred = true;
439 
440  delete current;
441  } else
442  ++it;
443  }
444 
445  if ( deletedPreferred ) {
446  IMAddressLVI *first = static_cast<IMAddressLVI*>( mWidget->lvAddresses->firstChild() );
447  if ( first ) {
448  first->setPreferred( true );
449  mPreferred = first->address();
450  } else
451  mPreferred = "";
452  }
453 
454  setModified( true );
455 }
456 
457 TQString IMEditorWidget::preferred() const
458 {
459  TQString retval( mPreferred );
460  return retval.replace( TQChar( 0xE120 ), " on " );
461 }
462 
463 
464 KPluginInfo * IMEditorWidget::protocolFromString( const TQString &fieldValue ) const
465 {
466  TQValueList<KPluginInfo *>::ConstIterator it;
467  KPluginInfo * protocol = 0;
468  for ( it = mProtocols.begin(); it != mProtocols.end(); ++it ) {
469  if ( (*it)->property( "X-TDE-InstantMessagingKABCField" ).toString() == fieldValue ) {
470  protocol = *it;
471  break;
472  }
473  }
474 
475  return protocol;
476 }
477 
478 void IMEditorWidget::splitField( const TQString &str, TQString &app, TQString &name, TQString &value )
479 {
480  int colon = str.find( ':' );
481  if ( colon != -1 ) {
482  TQString tmp = str.left( colon );
483  value = str.mid( colon + 1 );
484 
485  int dash = tmp.find( '-' );
486  if ( dash != -1 ) {
487  app = tmp.left( dash );
488  name = tmp.mid( dash + 1 );
489  }
490  }
491 }
492 
493 #include "imeditorwidget.moc"
List view item representing a single IM address.
A widget for editing an instant messaging address.
static void splitField(const TQString &str, TQString &app, TQString &name, TQString &value)
Helper method to split the contents of an addressbook field up.
KPluginInfo * protocolFromString(const TQString &fieldValue) const
Find a protocol that matches the KABC key, or 0 if none found.