kaddressbook

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"