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
46IMAddressLVI::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
56void IMAddressLVI::setPreferred( bool preferred )
57{
58 mPreferred = preferred;
59}
60
61bool IMAddressLVI::preferred() const
62{
63 return mPreferred;
64}
65
66void 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
78void 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
94void 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
113void IMAddressLVI::setProtocol( KPluginInfo *protocol )
114{
115 mProtocol = protocol;
116
117 setPixmap( 0, SmallIcon( mProtocol->icon() ) );
118 setText( 0, mProtocol->name() );
119}
120
121KPluginInfo * IMAddressLVI::protocol() const
122{
123 return mProtocol;
124}
125
126IMContext IMAddressLVI::context() const
127{
128 return mContext;
129}
130
131TQString IMAddressLVI::address() const
132{
133 return mAddress;
134}
135
136void IMAddressLVI::activate()
137{
138 // show editor
139}
140
141/*===========================================================================*/
142
143IMEditorWidget::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
188TQValueList<KPluginInfo *> IMEditorWidget::availableProtocols() const
189{
190 return mProtocols;
191}
192
193void 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
230void 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
253void IMEditorWidget::setReadOnly( bool readOnly )
254{
255 mReadOnly = readOnly;
256 slotUpdateButtons();
257}
258
259void 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
289void 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
322void IMEditorWidget::setModified( bool modified )
323{
324 mModified = modified;
325}
326
327bool IMEditorWidget::isModified() const
328{
329 return mModified;
330}
331
332void 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
363void 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
409void 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
457TQString IMEditorWidget::preferred() const
458{
459 TQString retval( mPreferred );
460 return retval.replace( TQChar( 0xE120 ), " on " );
461}
462
463
464KPluginInfo * 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
478void 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.