imeditorwidget.cpp
00001 /* 00002 IM address editor widget for KAddressBook 00003 00004 Copyright (c) 2004 Will Stephenson <lists@stevello.free-online.co.uk> 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 00020 As a special exception, permission is given to link this program 00021 with any edition of TQt, and distribute the resulting executable, 00022 without including the source code for TQt in the source distribution. 00023 */ 00024 00025 #include <tqlistview.h> 00026 #include <tqstringlist.h> 00027 #include <tqvbox.h> 00028 #include <tqlayout.h> 00029 #include <tqfont.h> 00030 #include <tqpainter.h> 00031 00032 #include <kdialogbase.h> 00033 #include <kdebug.h> 00034 #include <kiconloader.h> 00035 #include <tdelocale.h> 00036 #include <tdemessagebox.h> 00037 #include <kplugininfo.h> 00038 #include <kpushbutton.h> 00039 #include <ktrader.h> 00040 00041 #include "imaddresswidget.h" 00042 #include "imeditorbase.h" 00043 #include "imeditorwidget.h" 00044 00045 00046 IMAddressLVI::IMAddressLVI( TDEListView *parent, KPluginInfo *protocol, 00047 const TQString &address, const IMContext &context ) 00048 : TDEListViewItem( parent ) 00049 { 00050 setProtocol( protocol ); 00051 setAddress( address ); 00052 setContext( context ); 00053 mPreferred = false; 00054 } 00055 00056 void IMAddressLVI::setPreferred( bool preferred ) 00057 { 00058 mPreferred = preferred; 00059 } 00060 00061 bool IMAddressLVI::preferred() const 00062 { 00063 return mPreferred; 00064 } 00065 00066 void IMAddressLVI::paintCell( TQPainter *p, const TQColorGroup &cg, 00067 int column, int width, int alignment ) 00068 { 00069 if ( mPreferred ) { 00070 TQFont font = p->font(); 00071 font.setBold( true ); 00072 p->setFont( font ); 00073 } 00074 00075 TDEListViewItem::paintCell( p, cg, column, width, alignment ); 00076 } 00077 00078 void IMAddressLVI::setAddress( const TQString &address ) 00079 { 00080 // irc uses 0xE120 to seperate the nick and the server group. 00081 TQString serverOrGroup = address.section( TQChar( 0xE120 ), 1 ); 00082 00083 if ( serverOrGroup.isEmpty() ) 00084 setText( 1, address ); 00085 else { 00086 TQString nickname = address.section( TQChar( 0xE120 ), 0, 0 ); 00087 setText( 1, i18n( "<nickname> on <server>","%1 on %2" ) 00088 .arg( nickname ).arg( serverOrGroup ) ); 00089 } 00090 00091 mAddress = address; 00092 } 00093 00094 void IMAddressLVI::setContext( const IMContext &context ) 00095 { 00096 mContext = context; 00097 // set context 00098 /* switch ( context ) 00099 { 00100 case Home: 00101 setText( 2, i18n( "Home" ) ); 00102 break; 00103 case Work: 00104 setText( 2, i18n( "Work" ) ); 00105 break; 00106 case Any: 00107 setText( 2, i18n( "Any" ) ); 00108 break; 00109 } 00110 */ 00111 } 00112 00113 void IMAddressLVI::setProtocol( KPluginInfo *protocol ) 00114 { 00115 mProtocol = protocol; 00116 00117 setPixmap( 0, SmallIcon( mProtocol->icon() ) ); 00118 setText( 0, mProtocol->name() ); 00119 } 00120 00121 KPluginInfo * IMAddressLVI::protocol() const 00122 { 00123 return mProtocol; 00124 } 00125 00126 IMContext IMAddressLVI::context() const 00127 { 00128 return mContext; 00129 } 00130 00131 TQString IMAddressLVI::address() const 00132 { 00133 return mAddress; 00134 } 00135 00136 void IMAddressLVI::activate() 00137 { 00138 // show editor 00139 } 00140 00141 /*===========================================================================*/ 00142 00143 IMEditorWidget::IMEditorWidget( TQWidget *parent, const TQString &preferredIM, const char *name ) 00144 : KDialogBase( parent, name, false, i18n( "Edit Instant Messenging Address" ), 00145 Help | Ok | Cancel, Ok, false ), 00146 mReadOnly( false ) 00147 { 00148 mWidget = new IMEditorBase( this ); 00149 setMainWidget( mWidget ); 00150 00151 connect( mWidget->btnAdd, TQT_SIGNAL( clicked() ), TQT_SLOT( slotAdd() ) ); 00152 connect( mWidget->btnEdit, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEdit() ) ); 00153 connect( mWidget->btnDelete, TQT_SIGNAL( clicked() ), TQT_SLOT( slotDelete() ) ); 00154 connect( mWidget->btnSetStandard, TQT_SIGNAL( clicked()), TQT_SLOT( slotSetStandard() ) ); 00155 connect( mWidget->lvAddresses, TQT_SIGNAL( selectionChanged() ), TQT_SLOT( slotUpdateButtons() ) ); 00156 00157 connect( mWidget->lvAddresses, TQT_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint&, int ) ), 00158 TQT_SLOT( slotEdit() ) ); 00159 00160 setHelp( "managing-contacts-im-addresses" ); 00161 00162 mWidget->btnEdit->setEnabled( false ); 00163 mWidget->btnDelete->setEnabled( false ); 00164 mWidget->btnSetStandard->setEnabled( false ); 00165 // Disabled pending implementation 00166 //mWidget->btnUp->setEnabled( false ); 00167 //mWidget->btnDown->setEnabled( false ); 00168 mPreferred = preferredIM; 00169 mPreferred = mPreferred.replace( " on ", TQString( TQChar( 0xE120 ) ), true ); 00170 mProtocols = KPluginInfo::fromServices( TDETrader::self()->query( TQString::fromLatin1( "KABC/IMProtocol" ) ) ); 00171 00172 // order the protocols by putting them in a qmap, then sorting the set of keys and recreating the list 00173 TQMap<TQString, KPluginInfo *> protocolMap; 00174 TQValueList<KPluginInfo *>::ConstIterator it; 00175 TQValueList<KPluginInfo *> sorted; 00176 for ( it = mProtocols.begin(); it != mProtocols.end(); ++it ) 00177 protocolMap.insert( (*it)->name(), (*it) ); 00178 00179 TQStringList keys = protocolMap.keys(); 00180 keys.sort(); 00181 TQStringList::ConstIterator keyIt = keys.begin(); 00182 TQStringList::ConstIterator end = keys.end(); 00183 for ( ; keyIt != end; ++keyIt ) 00184 sorted.append( protocolMap[*keyIt] ); 00185 mProtocols = sorted; 00186 } 00187 00188 TQValueList<KPluginInfo *> IMEditorWidget::availableProtocols() const 00189 { 00190 return mProtocols; 00191 } 00192 00193 void IMEditorWidget::loadContact( TDEABC::Addressee *addr ) 00194 { 00195 if ( mWidget->lvAddresses ) 00196 mWidget->lvAddresses->clear(); 00197 00198 // see README for details of how Evolution stores IM addresses (differently) 00199 const TQStringList customs = addr->customs(); 00200 00201 TQStringList::ConstIterator it; 00202 bool isSet = false; 00203 for ( it = customs.begin(); it != customs.end(); ++it ) { 00204 TQString app, name, value; 00205 splitField( *it, app, name, value ); 00206 00207 if ( app.startsWith( TQString::fromLatin1( "messaging/" ) ) ) { 00208 if ( name == TQString::fromLatin1( "All" ) ) { 00209 KPluginInfo *protocol = protocolFromString( app ); 00210 if ( protocol ) { 00211 TQStringList addresses = TQStringList::split( TQChar( 0xE000 ), value ); 00212 TQStringList::iterator end = addresses.end(); 00213 for ( TQStringList::ConstIterator it = addresses.begin(); it != end; ++it ) { 00214 IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, protocol, *it, Any/*, false*/ ); 00215 if ( !isSet && (*it).stripWhiteSpace().lower() == mPreferred.stripWhiteSpace().lower() ) { 00216 imaddresslvi->setPreferred( true ); 00217 isSet = true; //Only set one item to be preferred 00218 } 00219 } 00220 } else 00221 kdDebug( 5720 ) << k_funcinfo << " no protocol found for: " << app << endl; 00222 } 00223 } 00224 } 00225 00226 if ( mWidget->lvAddresses->firstChild() ) 00227 mWidget->lvAddresses->firstChild()->setSelected( true ); 00228 } 00229 00230 void IMEditorWidget::storeContact( TDEABC::Addressee *addr ) 00231 { 00232 // for each changed protocol, write a new custom field containing the current set of 00233 // addresses 00234 TQValueList<KPluginInfo *>::ConstIterator protocolIt; 00235 for ( protocolIt = mChangedProtocols.begin(); protocolIt != mChangedProtocols.end(); ++protocolIt ) { 00236 TQStringList lst; 00237 TQListViewItemIterator addressIt( mWidget->lvAddresses ); 00238 while ( addressIt.current() ) { 00239 IMAddressLVI* currentAddress = static_cast<IMAddressLVI*>( *addressIt ); 00240 if ( currentAddress->protocol() == *protocolIt ) 00241 lst.append( currentAddress->address() ); 00242 ++addressIt; 00243 } 00244 00245 TQString addrBookField = (*protocolIt)->property( "X-TDE-InstantMessagingKABCField" ).toString(); 00246 if ( !lst.isEmpty() ) 00247 addr->insertCustom( addrBookField, TQString::fromLatin1( "All" ), lst.join( TQChar( 0xE000 ) ) ); 00248 else 00249 addr->removeCustom( addrBookField, TQString::fromLatin1( "All" ) ); 00250 } 00251 } 00252 00253 void IMEditorWidget::setReadOnly( bool readOnly ) 00254 { 00255 mReadOnly = readOnly; 00256 slotUpdateButtons(); 00257 } 00258 00259 void IMEditorWidget::slotSetStandard() 00260 { 00261 TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected ); 00262 00263 // Just set the first one selected as standard 00264 if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) { 00265 TQListViewItemIterator it2( mWidget->lvAddresses ); 00266 while ( it2.current() ) { 00267 IMAddressLVI *item = static_cast<IMAddressLVI*>( it2.current() ); 00268 00269 if ( item->preferred() ) { 00270 if ( current == item ) 00271 return; //Selected is already preferred 00272 else { 00273 item->setPreferred( false ); 00274 mWidget->lvAddresses->repaintItem( item ); 00275 break; 00276 } 00277 } 00278 00279 ++it2; 00280 } 00281 00282 mPreferred = current->address(); 00283 current->setPreferred( true ); 00284 setModified( true ); 00285 mWidget->lvAddresses->repaintItem( current ); 00286 } 00287 } 00288 00289 void IMEditorWidget::slotUpdateButtons() 00290 { 00291 int num_selected = 0; 00292 TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected ); 00293 while ( it.current() ) { 00294 ++num_selected; 00295 if ( num_selected > 1 ) 00296 break; //no need to count above 2. 00297 00298 ++it; 00299 } 00300 00301 if ( !mReadOnly && num_selected == 1 ) { 00302 mWidget->btnAdd->setEnabled( true ); 00303 mWidget->btnEdit->setEnabled( true ); 00304 mWidget->btnDelete->setEnabled( true ); 00305 IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ); 00306 00307 // Disable "set standard" if already standard 00308 mWidget->btnSetStandard->setEnabled( !current || !current->preferred() ); 00309 } else if ( !mReadOnly && num_selected > 1 ) { 00310 mWidget->btnAdd->setEnabled( true ); 00311 mWidget->btnEdit->setEnabled( false ); 00312 mWidget->btnDelete->setEnabled( true ); 00313 mWidget->btnSetStandard->setEnabled( false ); 00314 } else { 00315 mWidget->btnAdd->setEnabled( !mReadOnly ); 00316 mWidget->btnSetStandard->setEnabled( false ); 00317 mWidget->btnEdit->setEnabled( false ); 00318 mWidget->btnDelete->setEnabled( false ); 00319 } 00320 } 00321 00322 void IMEditorWidget::setModified( bool modified ) 00323 { 00324 mModified = modified; 00325 } 00326 00327 bool IMEditorWidget::isModified() const 00328 { 00329 return mModified; 00330 } 00331 00332 void IMEditorWidget::slotAdd() 00333 { 00334 KDialogBase addDialog( this, "addaddress", true, i18n( "Instant messaging", "Add Address" ), 00335 KDialogBase::Ok | KDialogBase::Cancel ); 00336 00337 IMAddressWidget *addressWid = new IMAddressWidget( &addDialog, mProtocols ); 00338 addDialog.enableButtonOK( false ); 00339 connect( addressWid, TQT_SIGNAL( inValidState( bool ) ), 00340 &addDialog, TQT_SLOT( enableButtonOK( bool ) ) ); 00341 addDialog.setMainWidget( addressWid ); 00342 00343 if ( addDialog.exec() == TQDialog::Accepted ) { 00344 // add the new item 00345 IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, addressWid->protocol(), 00346 addressWid->address() /*, addressWid->context() */ ); 00347 00348 // If it's a new address, set is as preferred. 00349 if ( mPreferred.isEmpty() ) { 00350 imaddresslvi->setPreferred( true ); 00351 mPreferred = addressWid->address(); 00352 } 00353 00354 if ( mChangedProtocols.find( addressWid->protocol() ) == mChangedProtocols.end() ) 00355 mChangedProtocols.append( addressWid->protocol() ); 00356 00357 mWidget->lvAddresses->sort(); 00358 00359 setModified( true ); 00360 } 00361 } 00362 00363 void IMEditorWidget::slotEdit() 00364 { 00365 if( mReadOnly ) 00366 return; 00367 TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected ); 00368 00369 // Just edit the first one selected. 00370 if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) { 00371 KDialogBase editDialog( this, "editaddress", true, i18n( "Instant messaging", "Edit Address" ), 00372 KDialogBase::Ok | KDialogBase::Cancel ); 00373 IMAddressWidget *addressWid = new IMAddressWidget( &editDialog, mProtocols, current->protocol(), 00374 current->address(), current->context() ) ; 00375 connect( addressWid, TQT_SIGNAL( inValidState( bool ) ), 00376 &editDialog, TQT_SLOT( enableButtonOK( bool ) ) ); 00377 editDialog.setMainWidget( addressWid ); 00378 00379 if ( editDialog.exec() == TQDialog::Accepted ) { 00380 bool modified = false; 00381 if ( addressWid->address() != current->address() ) { 00382 modified = true; 00383 current->setAddress( addressWid->address() ); 00384 } 00385 if ( addressWid->context() != current->context() ) { 00386 modified = true; 00387 current->setContext( addressWid->context() ); 00388 } 00389 00390 // the entry for the protocol of the current address has changed 00391 if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) { 00392 mChangedProtocols.append( current->protocol() ); 00393 } 00394 // update protocol - has another protocol gained an address? 00395 if ( current->protocol() != addressWid->protocol() ) { 00396 modified = true; 00397 // this proto is losing an entry 00398 current->setProtocol( addressWid->protocol() ); 00399 if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) 00400 mChangedProtocols.append( current->protocol() ); 00401 } 00402 00403 if ( modified ) 00404 setModified(true); 00405 } 00406 } 00407 } 00408 00409 void IMEditorWidget::slotDelete() 00410 { 00411 int num_selected = 0; 00412 00413 { 00414 TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected ); 00415 while ( it.current() ) { 00416 num_selected++; 00417 ++it; 00418 } 00419 } 00420 00421 if ( num_selected == 0 ) 00422 return; 00423 00424 if ( KMessageBox::warningContinueCancel( this, i18n( "Do you really want to delete the selected address?", 00425 "Do you really want to delete the %n selected addresses?", num_selected ), 00426 i18n( "Confirm Delete" ), KStdGuiItem::del() ) != KMessageBox::Continue ) 00427 return; 00428 00429 TQListViewItemIterator it( mWidget->lvAddresses ); 00430 bool deletedPreferred = false; 00431 while( it.current() ) { 00432 if ( it.current()->isSelected() ) { 00433 IMAddressLVI * current = static_cast<IMAddressLVI*>( *it ); 00434 if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) 00435 mChangedProtocols.append( current->protocol() ); 00436 00437 if ( current->preferred() ) 00438 deletedPreferred = true; 00439 00440 delete current; 00441 } else 00442 ++it; 00443 } 00444 00445 if ( deletedPreferred ) { 00446 IMAddressLVI *first = static_cast<IMAddressLVI*>( mWidget->lvAddresses->firstChild() ); 00447 if ( first ) { 00448 first->setPreferred( true ); 00449 mPreferred = first->address(); 00450 } else 00451 mPreferred = ""; 00452 } 00453 00454 setModified( true ); 00455 } 00456 00457 TQString IMEditorWidget::preferred() const 00458 { 00459 TQString retval( mPreferred ); 00460 return retval.replace( TQChar( 0xE120 ), " on " ); 00461 } 00462 00463 00464 KPluginInfo * IMEditorWidget::protocolFromString( const TQString &fieldValue ) const 00465 { 00466 TQValueList<KPluginInfo *>::ConstIterator it; 00467 KPluginInfo * protocol = 0; 00468 for ( it = mProtocols.begin(); it != mProtocols.end(); ++it ) { 00469 if ( (*it)->property( "X-TDE-InstantMessagingKABCField" ).toString() == fieldValue ) { 00470 protocol = *it; 00471 break; 00472 } 00473 } 00474 00475 return protocol; 00476 } 00477 00478 void IMEditorWidget::splitField( const TQString &str, TQString &app, TQString &name, TQString &value ) 00479 { 00480 int colon = str.find( ':' ); 00481 if ( colon != -1 ) { 00482 TQString tmp = str.left( colon ); 00483 value = str.mid( colon + 1 ); 00484 00485 int dash = tmp.find( '-' ); 00486 if ( dash != -1 ) { 00487 app = tmp.left( dash ); 00488 name = tmp.mid( dash + 1 ); 00489 } 00490 } 00491 } 00492 00493 #include "imeditorwidget.moc"