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 Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qlistview.h>
00026 #include <qstringlist.h>
00027 #include <qvbox.h>
00028 #include <qlayout.h>
00029 #include <qfont.h>
00030 #include <qpainter.h>
00031 
00032 #include <kdialogbase.h>
00033 #include <kdebug.h>
00034 #include <kiconloader.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.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( KListView *parent, KPluginInfo *protocol,
00047                             const QString &address, const IMContext &context )
00048   : KListViewItem( 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( QPainter *p, const QColorGroup &cg,
00067                               int column, int width, int alignment )
00068 {
00069   if ( mPreferred ) {
00070     QFont font = p->font();
00071     font.setBold( true );
00072     p->setFont( font );
00073   }
00074 
00075   KListViewItem::paintCell( p, cg, column, width, alignment );
00076 }
00077 
00078 void IMAddressLVI::setAddress( const QString &address )
00079 {
00080   // irc uses 0xE120 to seperate the nick and the server group.
00081   QString serverOrGroup = address.section( QChar( 0xE120 ), 1 );
00082 
00083   if ( serverOrGroup.isEmpty() )
00084     setText( 1, address );
00085   else {
00086     QString nickname = address.section( QChar( 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 QString IMAddressLVI::address() const
00132 {
00133   return mAddress;
00134 }
00135 
00136 void IMAddressLVI::activate()
00137 {
00138   // show editor
00139 }
00140 
00141 /*===========================================================================*/
00142 
00143 IMEditorWidget::IMEditorWidget( QWidget *parent, const QString &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, SIGNAL( clicked() ), SLOT( slotAdd() ) );
00152   connect( mWidget->btnEdit, SIGNAL( clicked() ), SLOT( slotEdit() ) );
00153   connect( mWidget->btnDelete, SIGNAL( clicked() ), SLOT( slotDelete() ) );
00154   connect( mWidget->btnSetStandard, SIGNAL( clicked()), SLOT( slotSetStandard() ) );
00155   connect( mWidget->lvAddresses, SIGNAL( selectionChanged() ), SLOT( slotUpdateButtons() ) );
00156 
00157   connect( mWidget->lvAddresses, SIGNAL( doubleClicked( QListViewItem*, const QPoint&, int ) ),
00158            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 ", QString( QChar( 0xE120 ) ), true );
00170   mProtocols = KPluginInfo::fromServices( KTrader::self()->query( QString::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   QMap<QString, KPluginInfo *> protocolMap;
00174   QValueList<KPluginInfo *>::ConstIterator it;
00175   QValueList<KPluginInfo *> sorted;
00176   for ( it = mProtocols.begin(); it != mProtocols.end(); ++it )
00177       protocolMap.insert( (*it)->name(), (*it) );
00178 
00179   QStringList keys = protocolMap.keys();
00180   keys.sort();
00181   QStringList::ConstIterator keyIt = keys.begin();  
00182   QStringList::ConstIterator end = keys.end();
00183   for ( ; keyIt != end; ++keyIt )
00184       sorted.append( protocolMap[*keyIt] );
00185   mProtocols = sorted;
00186 }
00187 
00188 QValueList<KPluginInfo *> IMEditorWidget::availableProtocols() const
00189 {
00190   return mProtocols;
00191 }
00192 
00193 void IMEditorWidget::loadContact( KABC::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 QStringList customs = addr->customs();
00200 
00201   QStringList::ConstIterator it;
00202   bool isSet = false;
00203   for ( it = customs.begin(); it != customs.end(); ++it ) {
00204     QString app, name, value;
00205     splitField( *it, app, name, value );
00206 
00207     if ( app.startsWith( QString::fromLatin1( "messaging/" ) ) ) {
00208       if ( name == QString::fromLatin1( "All" ) ) {
00209         KPluginInfo *protocol = protocolFromString( app );
00210         if ( protocol ) {
00211           QStringList addresses = QStringList::split( QChar( 0xE000 ), value );
00212           QStringList::iterator end = addresses.end();
00213           for ( QStringList::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( KABC::Addressee *addr )
00231 {
00232   // for each changed protocol, write a new custom field containing the current set of
00233   // addresses
00234   QValueList<KPluginInfo *>::ConstIterator protocolIt;
00235   for ( protocolIt = mChangedProtocols.begin(); protocolIt != mChangedProtocols.end(); ++protocolIt ) {
00236     QStringList lst;
00237     QListViewItemIterator 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     QString addrBookField = (*protocolIt)->property( "X-KDE-InstantMessagingKABCField" ).toString();
00246     if ( !lst.isEmpty() )
00247       addr->insertCustom( addrBookField, QString::fromLatin1( "All" ), lst.join( QChar( 0xE000 ) ) );
00248     else
00249       addr->removeCustom( addrBookField, QString::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   QListViewItemIterator it( mWidget->lvAddresses, QListViewItemIterator::Selected );
00262 
00263   // Just set the first one selected as standard
00264   if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
00265     QListViewItemIterator 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   QListViewItemIterator it( mWidget->lvAddresses, QListViewItemIterator::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( "Add Address" ),
00335                          KDialogBase::Ok | KDialogBase::Cancel );
00336 
00337   IMAddressWidget *addressWid = new IMAddressWidget( &addDialog, mProtocols );
00338   addDialog.enableButtonOK( false );
00339   connect( addressWid, SIGNAL( inValidState( bool ) ),
00340            &addDialog, SLOT( enableButtonOK( bool ) ) );
00341   addDialog.setMainWidget( addressWid );
00342 
00343   if ( addDialog.exec() == QDialog::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   QListViewItemIterator it( mWidget->lvAddresses, QListViewItemIterator::Selected );
00366 
00367   // Just edit the first one selected.
00368   if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
00369     KDialogBase editDialog( this, "editaddress", true, i18n( "Edit Address" ),
00370                             KDialogBase::Ok | KDialogBase::Cancel );
00371     IMAddressWidget *addressWid = new IMAddressWidget( &editDialog, mProtocols, current->protocol(),
00372                                                        current->address(), current->context() ) ;
00373     connect( addressWid, SIGNAL( inValidState( bool ) ),
00374              &editDialog, SLOT( enableButtonOK( bool ) ) );
00375     editDialog.setMainWidget( addressWid );
00376 
00377     if ( editDialog.exec() == QDialog::Accepted ) {
00378       bool modified = false;
00379       if ( addressWid->address() != current->address() ) {
00380         modified = true;
00381         current->setAddress( addressWid->address() );
00382       }
00383       if ( addressWid->context() != current->context() ) {
00384         modified = true;
00385         current->setContext( addressWid->context() );
00386       }
00387 
00388       // the entry for the protocol of the current address has changed
00389       if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) {
00390         mChangedProtocols.append( current->protocol() );
00391       }
00392       // update protocol - has another protocol gained an address?
00393       if ( current->protocol() != addressWid->protocol() ) {
00394         modified = true;
00395         // this proto is losing an entry
00396         current->setProtocol( addressWid->protocol() );
00397         if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
00398           mChangedProtocols.append( current->protocol() );
00399       }
00400 
00401       if ( modified )
00402         setModified(true);
00403     }
00404   }
00405 }
00406 
00407 void IMEditorWidget::slotDelete()
00408 {
00409   int num_selected = 0;
00410 
00411   {
00412     QListViewItemIterator it( mWidget->lvAddresses, QListViewItemIterator::Selected );
00413     while ( it.current() ) {
00414       num_selected++;
00415       ++it;
00416     }
00417   }
00418 
00419   if ( num_selected == 0 )
00420     return;
00421 
00422   if ( KMessageBox::warningContinueCancel( this, i18n( "Do you really want to delete the selected address?",
00423                                            "Do you really want to delete the %n selected addresses?", num_selected ),
00424                                            i18n( "Confirm Delete" ), KStdGuiItem::del() ) != KMessageBox::Continue )
00425     return;
00426 
00427   QListViewItemIterator it( mWidget->lvAddresses );
00428   bool deletedPreferred = false;
00429   while( it.current() ) {
00430     if ( it.current()->isSelected() ) {
00431       IMAddressLVI * current = static_cast<IMAddressLVI*>( *it );
00432       if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
00433         mChangedProtocols.append( current->protocol() );
00434 
00435       if ( current->preferred() )
00436         deletedPreferred = true;
00437 
00438       delete current;
00439     } else
00440       ++it;
00441   }
00442 
00443   if ( deletedPreferred ) {
00444     IMAddressLVI *first = static_cast<IMAddressLVI*>( mWidget->lvAddresses->firstChild() );
00445     if ( first ) {
00446       first->setPreferred( true );
00447       mPreferred = first->address();
00448     } else
00449       mPreferred = "";
00450   }
00451 
00452   setModified( true );
00453 }
00454 
00455 QString IMEditorWidget::preferred() const
00456 {
00457   QString retval( mPreferred );
00458   return retval.replace( QChar( 0xE120 ), " on " );
00459 }
00460 
00461 
00462 KPluginInfo * IMEditorWidget::protocolFromString( const QString &fieldValue ) const
00463 {
00464   QValueList<KPluginInfo *>::ConstIterator it;
00465   KPluginInfo * protocol = 0;
00466   for ( it = mProtocols.begin(); it != mProtocols.end(); ++it ) {
00467     if ( (*it)->property( "X-KDE-InstantMessagingKABCField" ).toString() == fieldValue ) {
00468       protocol = *it;
00469       break;
00470     }
00471   }
00472 
00473   return protocol;
00474 }
00475 
00476 void IMEditorWidget::splitField( const QString &str, QString &app, QString &name, QString &value )
00477 {
00478   int colon = str.find( ':' );
00479   if ( colon != -1 ) {
00480     QString tmp = str.left( colon );
00481     value = str.mid( colon + 1 );
00482 
00483     int dash = tmp.find( '-' );
00484     if ( dash != -1 ) {
00485       app = tmp.left( dash );
00486       name = tmp.mid( dash + 1 );
00487     }
00488   }
00489 }
00490 
00491 #include "imeditorwidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys