2
kopetestatusmanager.cpp - Kopete Status Manager
4
Copyright (c) 2008 by Roman Jarosz <kedgedev@centrum.cz>
5
Kopete (c) 2008 by the Kopete developers <kopete-devel@kde.org>
7
*************************************************************************
9
* This library is free software; you can redistribute it and/or *
10
* modify it under the terms of the GNU Lesser General Public *
11
* License as published by the Free Software Foundation; either *
12
* version 2 of the License, or (at your option) any later version. *
14
*************************************************************************
16
#include "kopetestatusmanager.h"
18
#include <QApplication>
19
#include <QtCore/QFile>
20
#include <QtXml/QDomElement>
21
#include <QtCore/QTimer>
23
#include <ksavefile.h>
24
#include <kstandarddirs.h>
26
#include <kmessagebox.h>
28
#include "kopeteuiglobal.h"
29
#include "kopeteaccountmanager.h"
30
#include "kopeteaccount.h"
31
#include "kopetecontact.h"
32
#include "kopeteonlinestatusmanager.h"
33
#include "kopetebehaviorsettings.h"
34
#include "kopetestatusitems.h"
35
#include "kopeteidletimer.h"
39
StatusManager *StatusManager::instance = 0L;
41
class StatusManager::Private
44
Status::StatusGroup *root;
45
QHash<QString, Status::StatusItem *> uidHash;
51
uint globalStatusCategory;
52
Kopete::StatusMessage globalStatusMessage;
53
Kopete::StatusMessage customStatusMessage;
56
QList<Kopete::Account*> autoAwayAccounts;
58
Kopete::IdleTimer* idleTimer;
61
StatusManager::StatusManager()
62
: QObject( qApp ), d( new Private )
70
loadBehaviorSettings();
71
connect( Kopete::BehaviorSettings::self(), SIGNAL(configChanged()),
72
this, SLOT(loadBehaviorSettings()) );
74
connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered(const Kopete::Account*)),
75
this, SLOT(accountUnregistered(const Kopete::Account*)));
77
connect( Kopete::AccountManager::self(), SIGNAL(accountOnlineStatusChanged(Kopete::Account*,Kopete::OnlineStatus,Kopete::OnlineStatus)),
78
this, SLOT(checkIdleTimer()));
82
StatusManager::~StatusManager()
92
void StatusManager::saveXML()
94
QString filename = KStandardDirs::locateLocal( "data", QLatin1String( "kopete/statuses.xml" ) );
95
KSaveFile file(filename);
98
QTextStream stream (&file);
99
stream.setCodec(QTextCodec::codecForName("UTF-8"));
101
QDomDocument doc( QString::fromLatin1( "kopete-statuses" ) );
102
doc.appendChild( StatusManager::storeStatusItem( d->root ) );
103
doc.save( stream, 4 );
109
void StatusManager::loadXML()
116
const QString filename = KStandardDirs::locateLocal( "data", QLatin1String( "kopete/statuses.xml" ) );
119
QFile file( filename );
120
if ( file.open( QIODevice::ReadOnly ) )
122
if ( doc.setContent( &file ) )
124
Kopete::Status::StatusItem* rootItem = StatusManager::parseStatusItem( doc.documentElement() );
127
if ( rootItem->isGroup() )
128
d->root = qobject_cast<Status::StatusGroup *>(rootItem);
138
d->root = defaultStatuses();
142
updateUidHash( d->root );
145
StatusManager *StatusManager::self()
148
instance = new StatusManager;
153
void StatusManager::setRootGroup( Kopete::Status::StatusGroup *rootGroup )
155
if ( !rootGroup || rootGroup == d->root )
162
updateUidHash( d->root );
167
Status::StatusGroup *StatusManager::getRootGroup() const
172
Kopete::Status::StatusGroup *StatusManager::copyRootGroup() const
174
return qobject_cast<Kopete::Status::StatusGroup *>(d->root->copy());
177
const Status::StatusItem *StatusManager::itemForUid( const QString &uid ) const
179
return d->uidHash.value( uid, 0 );
182
QDomElement StatusManager::storeStatusItem( const Status::StatusItem *item )
184
QDomDocument statusDoc;
185
QString rootName = ( item->isGroup() ) ? QLatin1String( "group" ) : QLatin1String( "status" );
186
statusDoc.appendChild( statusDoc.createElement( rootName ) );
187
statusDoc.documentElement().setAttribute( "uid", item->uid() );
188
statusDoc.documentElement().setAttribute( "category", item->category() );
190
QDomElement title = statusDoc.createElement( QLatin1String( "title" ) );
191
title.appendChild( statusDoc.createTextNode( item->title() ) );
192
statusDoc.documentElement().appendChild( title );
194
if ( item->isGroup() )
196
const Status::StatusGroup *group = qobject_cast<const Kopete::Status::StatusGroup*>( item );
197
const QList<Status::StatusItem *> childs = group->childList();
198
foreach ( Status::StatusItem *child , childs )
199
statusDoc.documentElement().appendChild( storeStatusItem( child ) );
203
const Status::Status *status = qobject_cast<const Kopete::Status::Status*>( item );
204
QDomElement message = statusDoc.createElement( QLatin1String( "message" ) );
205
message.appendChild( statusDoc.createTextNode( status->message() ) );
206
statusDoc.documentElement().appendChild( message );
209
return statusDoc.documentElement();
212
Status::StatusItem *StatusManager::parseStatusItem( QDomElement element )
214
if ( element.isNull() )
217
if ( element.tagName() == QString::fromUtf8( "group" ) )
219
Status::StatusGroup* group = new Status::StatusGroup( element.attribute( "uid" ) );
220
group->setCategory( (OnlineStatusManager::Category)element.attribute( "category", "0" ).toInt() );
222
QDomNode childNode = element.firstChild();
223
while ( !childNode.isNull() )
225
QDomElement childElement = childNode.toElement();
226
if ( childElement.tagName() == QLatin1String( "title" ) )
227
group->setTitle( childElement.text() );
228
else if ( childElement.tagName() == QLatin1String( "group" ) || childElement.tagName() == QLatin1String( "status" ) )
230
Status::StatusItem *item = StatusManager::parseStatusItem( childElement );
232
group->appendChild( item );
234
childNode = childNode.nextSibling();
238
else if ( element.tagName() == QString::fromUtf8( "status" ) )
240
Status::Status* status = new Status::Status( element.attribute( "uid" ) );
241
status->setCategory( (OnlineStatusManager::Category)element.attribute( "category", "0" ).toInt() );
243
QDomNode childNode = element.firstChild();
244
while ( !childNode.isNull() )
246
QDomElement childElement = childNode.toElement();
247
if ( childElement.tagName() == QLatin1String( "title" ) )
248
status->setTitle( childElement.text() );
249
else if ( childElement.tagName() == QLatin1String( "message" ) )
250
status->setMessage( childElement.text() );
252
childNode = childNode.nextSibling();
260
void StatusManager::updateUidHash( Status::StatusItem *item )
262
if ( item->isGroup() )
264
Kopete::Status::StatusGroup *group = qobject_cast<Kopete::Status::StatusGroup*>(item);
265
QList<Kopete::Status::StatusItem*> childs = group->childList();
266
foreach( Kopete::Status::StatusItem* child, childs )
267
updateUidHash( child );
271
d->uidHash[item->uid()] = item;
275
Status::StatusGroup *StatusManager::defaultStatuses() const
277
Status::StatusGroup* group = new Status::StatusGroup();
279
Status::Status* status = new Status::Status();
280
status->setTitle( i18n( "Online" ) );
281
status->setCategory( OnlineStatusManager::Online );
282
group->appendChild( status );
284
status = new Status::Status();
285
status->setTitle( i18n( "Away" ) );
286
status->setMessage( i18n( "I am gone right now, but I will be back later" ) );
287
status->setCategory( OnlineStatusManager::Away );
288
group->appendChild( status );
290
status = new Status::Status();
291
status->setTitle( i18n( "Busy" ) );
292
status->setMessage( i18n( "Sorry, I am busy right now" ) );
293
status->setCategory( OnlineStatusManager::Busy );
294
group->appendChild( status );
296
status = new Status::Status();
297
status->setTitle( i18n( "Invisible" ) );
298
status->setCategory( OnlineStatusManager::Invisible );
299
group->appendChild( status );
301
status = new Status::Status();
302
status->setTitle( i18n( "Offline" ) );
303
status->setCategory( OnlineStatusManager::Offline );
304
group->appendChild( status );
309
void StatusManager::setGlobalStatus( uint category, const Kopete::StatusMessage &statusMessage )
311
d->globalStatusCategory = category;
312
d->globalStatusMessage = statusMessage;
314
KConfigGroup config( KGlobal::config(), "Status Manager" );
315
config.writeEntry( "GlobalStatusCategory", d->globalStatusCategory );
316
config.writeEntry( "GlobalStatusTitle", d->globalStatusMessage.title() );
317
config.writeEntry( "GlobalStatusMessage", d->globalStatusMessage.message() );
320
emit globalStatusChanged();
323
void StatusManager::setGlobalStatusMessage( const Kopete::StatusMessage &statusMessage )
325
d->globalStatusMessage = statusMessage;
327
KConfigGroup config( KGlobal::config(), "Status Manager" );
328
config.writeEntry( "GlobalStatusTitle", d->globalStatusMessage.title() );
329
config.writeEntry( "GlobalStatusMessage", d->globalStatusMessage.message() );
332
// Iterate each connected account, updating its status message but keeping the
333
// same onlinestatus.
334
QList<Kopete::Account*> accountList = Kopete::AccountManager::self()->accounts();
335
foreach ( Kopete::Account *account, accountList )
337
Kopete::Contact *self = account->myself();
338
bool isInvisible = self && self->onlineStatus().status() == Kopete::OnlineStatus::Invisible;
339
if ( self && account->isConnected() && !isInvisible )
341
account->setOnlineStatus ( self->onlineStatus(), statusMessage );
345
emit globalStatusChanged();
348
Kopete::StatusMessage StatusManager::globalStatusMessage() const
350
return d->globalStatusMessage;
353
uint StatusManager::globalStatusCategory() const
355
return d->globalStatusCategory;
358
void StatusManager::askAndSetActive()
360
kDebug(14010) << "Found Activity. Confirming if we should go active";
362
// First Create a Dialog
363
KDialog *dialog = new KDialog(Kopete::UI::Global::mainWidget());
364
dialog->setCaption(i18n("Going Online - Kopete"));
365
dialog->setButtons(KDialog::Yes | KDialog::No);
366
dialog->setDefaultButton(KDialog::Yes);
367
dialog->setEscapeButton(KDialog::No);
368
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
370
// Set the Text in the Dialog
371
KMessageBox::createKMessageBox(dialog, QMessageBox::Question,
372
i18n("Do You Want to Change Status to Available?"),
373
QStringList(), QString(), NULL, KMessageBox::NoExec);
375
// If yes is clicked, go online
376
connect(dialog, SIGNAL(yesClicked()), this, SLOT(setActive()));
378
// If the user does not click something by the time we go away, kill the dialog
379
QTimer::singleShot(Kopete::BehaviorSettings::self()->autoAwayTimeout() * 1000, dialog, SLOT(close()));
385
void StatusManager::setActive()
387
kDebug(14010) << "Found activity on desktop, setting accounts online";
391
if ( d->goAvailable )
393
QList<Kopete::Account*>::iterator it, itEnd = d->autoAwayAccounts.end();
394
for( it = d->autoAwayAccounts.begin(); it != itEnd; ++it )
396
if( (*it)->isConnected() && (*it)->isAway() )
398
(*it)->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( (*it)->protocol(),
399
Kopete::OnlineStatusManager::Online ), globalStatusMessage(), Kopete::Account::KeepSpecialFlags );
402
d->autoAwayAccounts.clear();
407
void StatusManager::setAutoAway()
409
kDebug(14010) << "Going AutoAway!";
414
// Set all accounts that are not away already to away.
415
// We remember them so later we only set the accounts to
416
// available that we set to away (and not the user).
417
QList<Kopete::Account *> accountList = Kopete::AccountManager::self()->accounts();
419
QList<Kopete::Account*>::iterator it, itEnd = accountList.end();
420
for( it = accountList.begin(); it != itEnd; ++it )
422
if( (*it)->myself()->onlineStatus().status() == Kopete::OnlineStatus::Online )
424
d->autoAwayAccounts.append( (*it) );
426
if( d->useCustomStatus )
428
// Display a specific away message
429
(*it)->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( (*it)->protocol(),
430
Kopete::OnlineStatusManager::Idle ), d->customStatusMessage, Kopete::Account::KeepSpecialFlags );
434
// Display the last global away message used
435
(*it)->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( (*it)->protocol(),
436
Kopete::OnlineStatusManager::Idle ), d->globalStatusMessage, Kopete::Account::KeepSpecialFlags );
443
bool StatusManager::autoAway()
448
bool StatusManager::globalAway()
450
return ( d->globalStatusCategory == OnlineStatusManager::Away ||
451
d->globalStatusCategory == OnlineStatusManager::ExtendedAway ||
452
d->globalStatusCategory == OnlineStatusManager::Busy ||
453
d->globalStatusCategory == OnlineStatusManager::Offline );
456
void StatusManager::accountUnregistered( const Kopete::Account *account )
458
d->autoAwayAccounts.removeAll( const_cast<Kopete::Account *>(account) );
461
void StatusManager::checkIdleTimer()
463
// TODO: should we check for d->autoAwayAccounts to see whether to stop the timer?
464
Kopete::IdleTimer* idleTimer = Kopete::IdleTimer::self();
465
idleTimer->unregisterTimeout( this );
467
if(Kopete::AccountManager::self()->isAnyAccountConnected()) {
468
if ( Kopete::BehaviorSettings::self()->useAutoAway() ) {
469
if (Kopete::BehaviorSettings::self()->autoAwayAskAvailable())
470
idleTimer->registerTimeout( d->awayTimeout, this, SLOT(askAndSetActive()), SLOT(setAutoAway()) );
472
idleTimer->registerTimeout( d->awayTimeout, this, SLOT(setActive()), SLOT(setAutoAway()) );
477
void StatusManager::loadSettings()
479
KConfigGroup config( KGlobal::config(), "Status Manager" );
480
d->globalStatusCategory = config.readEntry( "GlobalStatusCategory", 0 );
482
Kopete::StatusMessage statusMessage;
483
statusMessage.setTitle( config.readEntry( "GlobalStatusTitle", QString() ) );
484
statusMessage.setMessage( config.readEntry( "GlobalStatusMessage", QString() ) );
485
d->globalStatusMessage = statusMessage;
488
void StatusManager::loadBehaviorSettings()
490
d->awayTimeout = Kopete::BehaviorSettings::self()->autoAwayTimeout();
491
d->goAvailable = Kopete::BehaviorSettings::self()->autoAwayGoAvailable();
492
d->useCustomStatus = Kopete::BehaviorSettings::self()->useCustomAwayMessage();
494
Kopete::StatusMessage customStatusMessage;
495
customStatusMessage.setTitle( Kopete::BehaviorSettings::self()->autoAwayCustomTitle() );
496
customStatusMessage.setMessage( Kopete::BehaviorSettings::self()->autoAwayCustomMessage() );
497
d->customStatusMessage = customStatusMessage;
504
#include "kopetestatusmanager.moc"