00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00149 if(d->connectionTry < 3)
00150 QTimer::singleShot(10000, this, SLOT(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
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
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
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
00351 c->setMetaContact(parent);
00352 return true;
00353 }
00354 else
00355 {
00356
00357 kDebug( 14010 ) << "Account::addContact: Contact already exists";
00358 }
00359 return 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
00376
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
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
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
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 * ,
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
00478
00479
00480
00481
00482
00483 d->suppressStatusNotification = true;
00484 d->suppressStatusTimer.setSingleShot( true );
00485 d->suppressStatusTimer.start( 5000 );
00486
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
00497
00498
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 * ,
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
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
00576
00577
00578
00579
00580
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 }
00611
00612 #include "kopeteaccount.moc"
00613