• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdenetwork
  • Sitemap
  • Contact Us
 

kopete/libkopete

kopeteaccount.cpp

Go to the documentation of this file.
00001 /*
00002     kopeteaccount.cpp - Kopete Account
00003 
00004     Copyright (c) 2003-2005 by Olivier Goffart       <ogoffart@kde.org>
00005     Copyright (c) 2003-2004 by Martijn Klingens      <klingens@kde.org>
00006     Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>
00007     Copyright (c) 2007         Will Stephenson       <wstephenson@kde.org>
00008 
00009     Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
00010 
00011     *************************************************************************
00012     *                                                                       *
00013     * This library is free software; you can redistribute it and/or         *
00014     * modify it under the terms of the GNU Lesser General Public            *
00015     * License as published by the Free Software Foundation; either          *
00016     * version 2 of the License, or (at your option) any later version.      *
00017     *                                                                       *
00018     *************************************************************************
00019 */
00020 
00021 #include <qapplication.h>
00022 #include <QTimer>
00023 #include <QPixmap>
00024 #include <QIcon>
00025 
00026 #include <kconfig.h>
00027 #include <kdebug.h>
00028 #include <kdialog.h>
00029 #include <kdeversion.h>
00030 #include <klocale.h>
00031 #include <kiconloader.h>
00032 #include <kiconeffect.h>
00033 #include <kicon.h>
00034 #include <kaction.h>
00035 #include <kmenu.h>
00036 #include <kmessagebox.h>
00037 #include <kcomponentdata.h>
00038 #include <kactionmenu.h>
00039 #include <kconfiggroup.h>
00040 
00041 #include "kopeteaccount.h"
00042 #include "kopeteidentity.h"
00043 #include "kopeteidentitymanager.h"
00044 #include "kabcpersistence.h"
00045 #include "kopetecontactlist.h"
00046 #include "kopeteaccountmanager.h"
00047 #include "kopetecontact.h"
00048 #include "kopetemetacontact.h"
00049 #include "kopeteprotocol.h"
00050 #include "kopetepluginmanager.h"
00051 #include "kopetegroup.h"
00052 #include "kopetebehaviorsettings.h"
00053 #include "kopeteutils.h"
00054 #include "kopeteuiglobal.h"
00055 #include "kopeteblacklister.h"
00056 #include "kopeteonlinestatusmanager.h"
00057 #include "editaccountwidget.h"
00058 
00059 namespace Kopete
00060 {
00061 
00062 
00063 class Account::Private
00064 {
00065 public:
00066     Private( Protocol *protocol, const QString &accountId )
00067      : protocol( protocol ), id( accountId )
00068      , excludeconnect( true ), priority( 0 )
00069      , connectionTry(0), identity( 0 ), myself( 0 )
00070      , suppressStatusTimer( 0 ), suppressStatusNotification( false )
00071      , blackList( new Kopete::BlackLister( protocol->pluginId(), accountId ) )
00072     { }
00073 
00074 
00075     ~Private() { delete blackList; }
00076 
00077     Protocol *protocol;
00078     QString id;
00079     QString accountLabel;
00080     bool excludeconnect;
00081     uint priority;
00082     QHash<QString, Contact*> contacts;
00083     QColor color;
00084     uint connectionTry;
00085     Identity *identity;
00086     Contact *myself;
00087     QTimer suppressStatusTimer;
00088     bool suppressStatusNotification;
00089     Kopete::BlackLister *blackList;
00090     KConfigGroup *configGroup;
00091     QString customIcon;
00092     Kopete::OnlineStatus restoreStatus;
00093     Kopete::StatusMessage restoreMessage;
00094 };
00095 
00096 Account::Account( Protocol *parent, const QString &accountId )
00097  : QObject( parent ), d( new Private( parent, accountId ) )
00098 {
00099     d->configGroup=new KConfigGroup(KGlobal::config(), QString::fromLatin1( "Account_%1_%2" ).arg( d->protocol->pluginId(), d->id ));
00100 
00101     d->excludeconnect = d->configGroup->readEntry( "ExcludeConnect", false );
00102     d->color = d->configGroup->readEntry( "Color" , QColor() );
00103     d->customIcon = d->configGroup->readEntry( "Icon", QString() );
00104     d->priority = d->configGroup->readEntry( "Priority", 0 );
00105 
00106     d->restoreStatus = Kopete::OnlineStatus::Online;
00107     d->restoreMessage = Kopete::StatusMessage();
00108 
00109     QObject::connect( &d->suppressStatusTimer, SIGNAL( timeout() ),
00110         this, SLOT( slotStopSuppression() ) );
00111 }
00112 
00113 Account::~Account()
00114 {
00115     d->contacts.remove( d->myself->contactId() );
00116     // Delete all registered child contacts first
00117     foreach (Contact* c, d->contacts) QObject::disconnect(c, SIGNAL( contactDestroyed( Kopete::Contact * ) ), this, 0);
00118     qDeleteAll(d->contacts);
00119     d->contacts.clear();
00120 
00121     kDebug( 14010 ) << " account '" << d->id << "' about to emit accountDestroyed ";
00122     emit accountDestroyed(this);
00123 
00124     delete d->myself;
00125     delete d->configGroup;
00126     delete d;
00127 }
00128 
00129 void Account::reconnect()
00130 {
00131     kDebug( 14010 ) << "account " << d->id << " restoreStatus " << d->restoreStatus.status()
00132                     << " restoreTitle " << d->restoreMessage.title()
00133                     << " restoreMessage " << d->restoreMessage.message();
00134     setOnlineStatus( d->restoreStatus, d->restoreMessage );
00135 }
00136 
00137 void Account::disconnected( DisconnectReason reason )
00138 {
00139     kDebug( 14010 ) << reason;
00140     //reconnect if needed
00141     if(reason == BadPassword )
00142     {
00143         QTimer::singleShot(0, this, SLOT(reconnect()));
00144     }
00145     else if ( Kopete::BehaviorSettings::self()->reconnectOnDisconnect() == true && reason > Manual )
00146     {
00147         d->connectionTry++;
00148         //use a timer to allow the plugins to clean up after return
00149         if(d->connectionTry < 3)
00150             QTimer::singleShot(10000, this, SLOT(reconnect())); // wait 10 seconds before reconnect
00151     }
00152     if(reason== OtherClient)
00153     {
00154         Kopete::Utils::notifyConnectionLost(this, i18n("You have been disconnected"), i18n( "You have connected from another client or computer to the account '%1'" , d->id), i18n("Most proprietary Instant Messaging services do not allow you to connect from more than one location. Check that nobody is using your account without your permission. If you need a service that supports connection from various locations at the same time, use the Jabber protocol."));
00155     }
00156 }
00157 
00158 Protocol *Account::protocol() const
00159 {
00160     return d->protocol;
00161 }
00162 
00163 QString Account::accountId() const
00164 {
00165     return d->id;
00166 }
00167 
00168 const QColor Account::color() const
00169 {
00170     return d->color;
00171 }
00172 
00173 void Account::setColor( const QColor &color )
00174 {
00175     d->color = color;
00176     if ( d->color.isValid() )
00177         d->configGroup->writeEntry( "Color", d->color );
00178     else
00179         d->configGroup->deleteEntry( "Color" );
00180     emit colorChanged( color );
00181 }
00182 
00183 void Account::setPriority( uint priority )
00184 {
00185     d->priority = priority;
00186     d->configGroup->writeEntry( "Priority", d->priority );
00187 }
00188 
00189 uint Account::priority() const
00190 {
00191     return d->priority;
00192 }
00193 
00194 
00195 QPixmap Account::accountIcon(const int size) const
00196 {
00197     QString icon= d->customIcon.isEmpty() ? d->protocol->pluginIcon() : d->customIcon;
00198 
00199     // FIXME: this code is duplicated with OnlineStatus, can we merge it somehow?
00200     QPixmap base = KIconLoader::global()->loadIcon(
00201         icon, KIconLoader::Small, size );
00202 
00203     if ( d->color.isValid() )
00204     {
00205         KIconEffect effect;
00206         base = effect.apply( base, KIconEffect::Colorize, 1, d->color, 0);
00207     }
00208 
00209     if ( size > 0 && base.width() != size )
00210     {
00211         base.scaled( size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
00212     }
00213 
00214     return base;
00215 }
00216 
00217 KConfigGroup* Kopete::Account::configGroup() const
00218 {
00219     return d->configGroup;
00220 }
00221 
00222 void Account::setAccountLabel( const QString &label )
00223 {
00224     d->accountLabel = label;
00225 }
00226 
00227 QString Account::accountLabel() const
00228 {
00229     if( d->accountLabel.isNull() )
00230         return d->id;
00231     return d->accountLabel;
00232 }
00233 
00234 void Account::setExcludeConnect( bool b )
00235 {
00236     d->excludeconnect = b;
00237     d->configGroup->writeEntry( "ExcludeConnect", d->excludeconnect );
00238 }
00239 
00240 bool Account::excludeConnect() const
00241 {
00242     return d->excludeconnect;
00243 }
00244 
00245 void Account::registerContact( Contact *c )
00246 {
00247     d->contacts.insert( c->contactId(), c );
00248     QObject::connect( c, SIGNAL( contactDestroyed( Kopete::Contact * ) ),
00249         SLOT( contactDestroyed( Kopete::Contact * ) ) );
00250 }
00251 
00252 void Account::contactDestroyed( Contact *c )
00253 {
00254     d->contacts.remove( c->contactId() );
00255 }
00256 
00257 
00258 const QHash<QString, Contact*>& Account::contacts()
00259 {
00260     return d->contacts;
00261 }
00262 
00263 
00264 Kopete::MetaContact* Account::addContact( const QString &contactId, const QString &displayName , Group *group, AddMode mode  )
00265 {
00266 
00267     if ( contactId == d->myself->contactId() )
00268     {
00269         KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error,
00270             i18n("You are not allowed to add yourself to the contact list. The addition of \"%1\" to account \"%2\" will not take place.", contactId, accountId()), i18n("Error Creating Contact")
00271         );
00272         return false;
00273     }
00274 
00275     bool isTemporary = mode == Temporary;
00276 
00277     Contact *c = d->contacts[ contactId ];
00278 
00279     if(!group)
00280         group=Group::topLevel();
00281 
00282     if ( c && c->metaContact() )
00283     {
00284         if ( c->metaContact()->isTemporary() && !isTemporary )
00285         {
00286             kDebug( 14010 ) <<  " You are trying to add an existing temporary contact. Just add it on the list";
00287 
00288             c->metaContact()->setTemporary(false, group );
00289             ContactList::self()->addMetaContact(c->metaContact());
00290         }
00291         else
00292         {
00293             // should we here add the contact to the parentContact if any?
00294             kDebug( 14010 ) << "Contact already exists";
00295         }
00296         return c->metaContact();
00297     }
00298 
00299     MetaContact *parentContact = new MetaContact();
00300     if(!displayName.isEmpty())
00301         parentContact->setDisplayName( displayName );
00302 
00303     //Set it as a temporary contact if requested
00304     if ( isTemporary )
00305         parentContact->setTemporary( true );
00306     else
00307         parentContact->addToGroup( group );
00308 
00309     if ( c )
00310     {
00311         c->setMetaContact( parentContact );
00312         if ( mode == ChangeKABC )
00313         {
00314             kDebug( 14010 ) << " changing KABC";
00315             KABCPersistence::self()->write( parentContact );
00316         }
00317     }
00318     else
00319     {
00320         if ( !createContact( contactId, parentContact ) )
00321         {
00322             delete parentContact;
00323             return 0L;
00324         }
00325     }
00326 
00327     ContactList::self()->addMetaContact( parentContact );
00328     return parentContact;
00329 }
00330 
00331 bool Account::addContact(const QString &contactId , MetaContact *parent, AddMode mode )
00332 {
00333     if ( contactId == myself()->contactId() )
00334     {
00335             KMessageBox::error( Kopete::UI::Global::mainWidget(),
00336             i18n("You are not allowed to add yourself to the contact list. The addition of \"%1\" to account \"%2\" will not take place.", contactId, accountId()), i18n("Error Creating Contact")
00337         );
00338         return 0L;
00339     }
00340 
00341     bool isTemporary= parent->isTemporary();
00342     Contact *c = d->contacts[ contactId ];
00343     if ( c && c->metaContact() )
00344     {
00345         if ( c->metaContact()->isTemporary() && !isTemporary )
00346         {
00347             kDebug( 14010 ) <<
00348                 "Account::addContact: You are trying to add an existing temporary contact. Just add it on the list" << endl;
00349 
00350                 //setMetaContact ill take care about the deletion of the old contact
00351             c->setMetaContact(parent);
00352             return true;
00353         }
00354         else
00355         {
00356             // should we here add the contact to the parentContact if any?
00357             kDebug( 14010 ) << "Account::addContact: Contact already exists";
00358         }
00359         return false; //(the contact is not in the correct metacontact, so false)
00360     }
00361 
00362     bool success = createContact(contactId, parent);
00363 
00364     if ( success && mode == ChangeKABC )
00365     {
00366         kDebug( 14010 ) << " changing KABC";
00367         KABCPersistence::self()->write( parent );
00368     }
00369 
00370     return success;
00371 }
00372 
00373 void Account::fillActionMenu( KActionMenu *actionMenu )
00374 {
00375     //default implementation
00376 //  KActionMenu *menu = new KActionMenu( QIcon(myself()->onlineStatus().iconFor( this )), accountId(), 0, 0);
00377 #ifdef __GNUC__
00378 #warning No icon shown, we should go away from QPixmap genered icons with overlays.
00379 #endif
00380     QString nick;
00381         if (identity()->hasProperty( Kopete::Global::Properties::self()->nickName().key() ))
00382         nick = identity()->property( Kopete::Global::Properties::self()->nickName() ).value().toString();
00383     else
00384         nick = myself()->nickName();
00385 
00386     // Always add title at the beginning of actionMenu
00387     QAction *before = actionMenu->menu()->actions().value( 0, 0 );
00388     actionMenu->menu()->addTitle( myself()->onlineStatus().iconFor( myself() ),
00389         nick.isNull() ? accountLabel() : i18n( "%2 <%1>", accountLabel(), nick ),
00390         before
00391     );
00392 
00393     actionMenu->menu()->addSeparator();
00394 
00395     KAction *propertiesAction = new KAction( i18n("Properties"), actionMenu );
00396     QObject::connect( propertiesAction, SIGNAL(triggered(bool)), this, SLOT( editAccount() ) );
00397     actionMenu->addAction( propertiesAction );
00398 }
00399 
00400 bool Account::hasCustomStatusMenu() const
00401 {
00402     return false;
00403 }
00404 
00405 bool Account::isConnected() const
00406 {
00407     return myself() && myself()->isOnline();
00408 }
00409 
00410 bool Account::isAway() const
00411 {
00412     return d->myself && ( d->myself->onlineStatus().status() == Kopete::OnlineStatus::Away );
00413 }
00414 Identity * Account::identity() const
00415 {
00416     return d->identity;
00417 }
00418 
00419 bool Account::setIdentity( Identity *ident )
00420 {
00421     if ( d->identity == ident )
00422     {
00423         return false;
00424     }
00425 
00426     if (d->identity)
00427     {
00428         d->identity->removeAccount( this );
00429     }
00430 
00431     ident->addAccount( this );
00432     d->identity = ident;
00433     d->configGroup->writeEntry("Identity", ident->id());
00434     return true;
00435 }
00436 
00437 Contact * Account::myself() const
00438 {
00439     return d->myself;
00440 }
00441 
00442 void Account::setMyself( Contact *myself )
00443 {
00444     //FIXME  does it make sens to change the myself contact to another ?   - Olivier 2005-11-21
00445 
00446     bool wasConnected = isConnected();
00447 
00448     if ( d->myself )
00449     {
00450         QObject::disconnect( d->myself, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
00451             this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
00452         QObject::disconnect( d->myself, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ),
00453             this, SLOT( slotContactPropertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ) );
00454     }
00455 
00456     d->myself = myself;
00457 
00458 //  d->contacts.remove( myself->contactId() );
00459 
00460     QObject::connect( d->myself, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
00461         this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
00462     QObject::connect( d->myself, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ),
00463         this, SLOT( slotContactPropertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ) );
00464 
00465     if ( isConnected() != wasConnected )
00466         emit isConnectedChanged();
00467 }
00468 
00469 void Account::slotOnlineStatusChanged( Contact * /* contact */,
00470     const OnlineStatus &newStatus, const OnlineStatus &oldStatus )
00471 {
00472     bool wasOffline = !oldStatus.isDefinitelyOnline();
00473     bool isOffline  = !newStatus.isDefinitelyOnline();
00474 
00475     if ( wasOffline || newStatus.status() == OnlineStatus::Offline )
00476     {
00477         // Wait for five seconds until we treat status notifications for contacts
00478         // as unrelated to our own status change.
00479         // Five seconds may seem like a long time, but just after your own
00480         // connection it's basically neglectible, and depending on your own
00481         // contact list's size, the protocol you are using, your internet
00482         // connection's speed and your computer's speed you *will* need it.
00483         d->suppressStatusNotification = true;
00484         d->suppressStatusTimer.setSingleShot( true );
00485         d->suppressStatusTimer.start( 5000 );
00486         //the timer is also used to reset the d->connectionTry
00487     }
00488 
00489     if ( !isOffline )
00490     {
00491         d->restoreStatus = newStatus;
00492         d->restoreMessage.setTitle( identity()->property( Kopete::Global::Properties::self()->statusTitle() ).value().toString() );
00493         d->restoreMessage.setMessage( identity()->property( Kopete::Global::Properties::self()->statusMessage() ).value().toString() );
00494     }
00495 
00496 /*  kDebug(14010) << "account " << d->id << " changed status. was "
00497                    << Kopete::OnlineStatus::statusTypeToString(oldStatus.status()) << ", is "
00498                    << Kopete::OnlineStatus::statusTypeToString(newStatus.status()) << endl;*/
00499     if ( wasOffline != isOffline )
00500         emit isConnectedChanged();
00501 }
00502 
00503 void Account::setAllContactsStatus( const Kopete::OnlineStatus &status )
00504 {
00505     d->suppressStatusNotification = true;
00506     d->suppressStatusTimer.setSingleShot( true );
00507     d->suppressStatusTimer.start( 5000 );
00508 
00509     QHashIterator<QString, Contact*> it(d->contacts);
00510     for (  ; it.hasNext(); ) {
00511         it.next();
00512         if ( it.value() != d->myself )
00513             it.value()->setOnlineStatus( status );
00514     }
00515 }
00516 
00517 void Account::slotContactPropertyChanged( PropertyContainer * /* contact */,
00518     const QString &key, const QVariant &old, const QVariant &newVal )
00519 {
00520     if ( key == Kopete::Global::Properties::self()->statusTitle().key() && old != newVal && isConnected() )
00521         d->restoreMessage.setTitle( newVal.toString() );
00522     else if ( key == Kopete::Global::Properties::self()->statusMessage().key() && old != newVal && isConnected() )
00523         d->restoreMessage.setMessage( newVal.toString() );
00524 }
00525 
00526 void Account::slotStopSuppression()
00527 {
00528     d->suppressStatusNotification = false;
00529     if(isConnected())
00530         d->connectionTry=0;
00531 }
00532 
00533 bool Account::suppressStatusNotification() const
00534 {
00535     return d->suppressStatusNotification;
00536 }
00537 
00538 bool Account::removeAccount()
00539 {
00540     //default implementation
00541     return true;
00542 }
00543 
00544 
00545 BlackLister* Account::blackLister()
00546 {
00547     return d->blackList;
00548 }
00549 
00550 void Account::block( const QString &contactId )
00551 {
00552     d->blackList->addContact( contactId );
00553 }
00554 
00555 void Account::unblock( const QString &contactId )
00556 {
00557     d->blackList->removeContact( contactId );
00558 }
00559 
00560 bool Account::isBlocked( const QString &contactId )
00561 {
00562     return d->blackList->isBlocked( contactId );
00563 }
00564 
00565 void Account::editAccount(QWidget *parent)
00566 {
00567     KDialog *editDialog = new KDialog( parent );
00568     editDialog->setCaption( i18n( "Edit Account" ) );
00569     editDialog->setButtons( KDialog::Ok | KDialog::Apply | KDialog::Cancel );
00570 
00571     KopeteEditAccountWidget *m_accountWidget = protocol()->createEditAccountWidget( this, editDialog );
00572     if ( !m_accountWidget )
00573         return;
00574 
00575     // FIXME: Why the #### is EditAccountWidget not a QWidget?!? This sideways casting
00576     //        is braindead and error-prone. Looking at MSN the only reason I can see is
00577     //        because it allows direct subclassing of designer widgets. But what is
00578     //        wrong with embedding the designer widget in an empty QWidget instead?
00579     //        Also, if this REALLY has to be a pure class and not a widget, then the
00580     //        class should at least be renamed to EditAccountIface instead - Martijn
00581     QWidget *w = dynamic_cast<QWidget *>( m_accountWidget );
00582     if ( !w )
00583         return;
00584 
00585     editDialog->setMainWidget( w );
00586     if ( editDialog->exec() == QDialog::Accepted )
00587     {
00588         if( m_accountWidget->validateData() )
00589             m_accountWidget->apply();
00590     }
00591 
00592     editDialog->deleteLater();
00593 }
00594 
00595 void Account::setCustomIcon( const QString & i)
00596 {
00597     d->customIcon = i;
00598     if(!i.isEmpty())
00599         d->configGroup->writeEntry( "Icon", i );
00600     else
00601         d->configGroup->deleteEntry( "Icon" );
00602     emit colorChanged( color() );
00603 }
00604 
00605 QString Account::customIcon()  const
00606 {
00607     return d->customIcon;
00608 }
00609 
00610 } // END namespace Kopete
00611 
00612 #include "kopeteaccount.moc"
00613 

kopete/libkopete

Skip menu "kopete/libkopete"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdenetwork

Skip menu "kdenetwork"
  • kget
  • kopete
  •   kopete
  •   libkopete
  •       libpapillon
  • krfb
Generated for kdenetwork by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal