~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to libkopete/kopetestatusmanager.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    kopetestatusmanager.cpp - Kopete Status Manager
 
3
 
 
4
    Copyright (c) 2008      by Roman Jarosz          <kedgedev@centrum.cz>
 
5
    Kopete    (c) 2008      by the Kopete developers <kopete-devel@kde.org>
 
6
 
 
7
    *************************************************************************
 
8
    *                                                                       *
 
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.      *
 
13
    *                                                                       *
 
14
    *************************************************************************
 
15
*/
 
16
#include "kopetestatusmanager.h"
 
17
 
 
18
#include <QApplication>
 
19
#include <QtCore/QFile>
 
20
#include <QtXml/QDomElement>
 
21
#include <QtCore/QTimer>
 
22
 
 
23
#include <ksavefile.h>
 
24
#include <kstandarddirs.h>
 
25
#include <kdialog.h>
 
26
#include <kmessagebox.h>
 
27
 
 
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"
 
36
 
 
37
namespace Kopete {
 
38
 
 
39
StatusManager *StatusManager::instance = 0L;
 
40
 
 
41
class StatusManager::Private
 
42
{
 
43
public:
 
44
        Status::StatusGroup *root;
 
45
        QHash<QString, Status::StatusItem *> uidHash;
 
46
 
 
47
        int awayTimeout;
 
48
        bool goAvailable;
 
49
        bool useCustomStatus;
 
50
 
 
51
        uint globalStatusCategory;
 
52
        Kopete::StatusMessage globalStatusMessage;
 
53
        Kopete::StatusMessage customStatusMessage;
 
54
        
 
55
        bool away;
 
56
        QList<Kopete::Account*> autoAwayAccounts;
 
57
 
 
58
        Kopete::IdleTimer* idleTimer;
 
59
};
 
60
 
 
61
StatusManager::StatusManager()
 
62
        : QObject( qApp ), d( new Private )
 
63
{
 
64
        d->away = false;
 
65
        d->root = 0;
 
66
        d->idleTimer = 0;
 
67
        loadXML();
 
68
 
 
69
        loadSettings();
 
70
        loadBehaviorSettings();
 
71
        connect( Kopete::BehaviorSettings::self(), SIGNAL(configChanged()),
 
72
                 this, SLOT(loadBehaviorSettings()) );
 
73
 
 
74
        connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered(const Kopete::Account*)),
 
75
                 this, SLOT(accountUnregistered(const Kopete::Account*)));
 
76
 
 
77
        connect( Kopete::AccountManager::self(), SIGNAL(accountOnlineStatusChanged(Kopete::Account*,Kopete::OnlineStatus,Kopete::OnlineStatus)),
 
78
                 this, SLOT(checkIdleTimer()));
 
79
 
 
80
}
 
81
 
 
82
StatusManager::~StatusManager()
 
83
{
 
84
        instance = 0L;
 
85
 
 
86
        delete d->idleTimer;
 
87
 
 
88
        delete d->root;
 
89
        delete d;
 
90
}
 
91
 
 
92
void StatusManager::saveXML()
 
93
{
 
94
        QString filename = KStandardDirs::locateLocal( "data", QLatin1String( "kopete/statuses.xml" ) );
 
95
        KSaveFile file(filename);
 
96
        if( file.open() )
 
97
        {
 
98
                QTextStream stream (&file);
 
99
                stream.setCodec(QTextCodec::codecForName("UTF-8"));
 
100
 
 
101
                QDomDocument doc( QString::fromLatin1( "kopete-statuses" ) );
 
102
                doc.appendChild( StatusManager::storeStatusItem( d->root ) );
 
103
                doc.save( stream, 4 );
 
104
 
 
105
                file.close();
 
106
        }
 
107
}
 
108
 
 
109
void StatusManager::loadXML()
 
110
{
 
111
        delete d->root;
 
112
 
 
113
        d->uidHash.clear();
 
114
        d->root = 0;
 
115
 
 
116
        const QString filename = KStandardDirs::locateLocal( "data", QLatin1String( "kopete/statuses.xml" ) );
 
117
 
 
118
        QDomDocument doc;
 
119
        QFile file( filename );
 
120
        if ( file.open( QIODevice::ReadOnly ) )
 
121
        {
 
122
                if ( doc.setContent( &file ) )
 
123
                {
 
124
                        Kopete::Status::StatusItem* rootItem = StatusManager::parseStatusItem( doc.documentElement() );
 
125
                        if ( rootItem )
 
126
                        {
 
127
                                if ( rootItem->isGroup() )
 
128
                                        d->root = qobject_cast<Status::StatusGroup *>(rootItem);
 
129
                                else
 
130
                                        delete rootItem;
 
131
                        }
 
132
                }
 
133
                file.close();
 
134
        }
 
135
        
 
136
        if ( !d->root )
 
137
        {
 
138
                d->root = defaultStatuses();
 
139
                saveXML();
 
140
        }
 
141
 
 
142
        updateUidHash( d->root );
 
143
}
 
144
 
 
145
StatusManager *StatusManager::self()
 
146
{
 
147
        if ( !instance )
 
148
                instance = new StatusManager;
 
149
 
 
150
        return instance;
 
151
}
 
152
 
 
153
void StatusManager::setRootGroup( Kopete::Status::StatusGroup *rootGroup )
 
154
{
 
155
        if ( !rootGroup || rootGroup == d->root )
 
156
                return;
 
157
 
 
158
        delete d->root;
 
159
 
 
160
        d->uidHash.clear();
 
161
        d->root = rootGroup;
 
162
        updateUidHash( d->root );
 
163
        
 
164
        emit changed();
 
165
}
 
166
 
 
167
Status::StatusGroup *StatusManager::getRootGroup() const
 
168
{
 
169
        return d->root;
 
170
}
 
171
 
 
172
Kopete::Status::StatusGroup *StatusManager::copyRootGroup() const
 
173
{
 
174
        return qobject_cast<Kopete::Status::StatusGroup *>(d->root->copy());
 
175
}
 
176
 
 
177
const Status::StatusItem *StatusManager::itemForUid( const QString &uid ) const
 
178
{
 
179
        return d->uidHash.value( uid, 0 );
 
180
}
 
181
 
 
182
QDomElement StatusManager::storeStatusItem( const Status::StatusItem *item )
 
183
{
 
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() );
 
189
 
 
190
        QDomElement title = statusDoc.createElement( QLatin1String( "title" ) );
 
191
        title.appendChild( statusDoc.createTextNode( item->title() ) );
 
192
        statusDoc.documentElement().appendChild( title );
 
193
 
 
194
        if ( item->isGroup() )
 
195
        {
 
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 ) );
 
200
        }
 
201
        else
 
202
        {
 
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 );
 
207
        }
 
208
 
 
209
        return statusDoc.documentElement();
 
210
}
 
211
 
 
212
Status::StatusItem *StatusManager::parseStatusItem( QDomElement element )
 
213
{
 
214
        if ( element.isNull() )
 
215
                return 0;
 
216
                
 
217
        if ( element.tagName() == QString::fromUtf8( "group" ) )
 
218
        {
 
219
                Status::StatusGroup* group = new Status::StatusGroup( element.attribute( "uid" ) );
 
220
                group->setCategory( (OnlineStatusManager::Category)element.attribute( "category", "0" ).toInt() );
 
221
 
 
222
                QDomNode childNode = element.firstChild();
 
223
                while ( !childNode.isNull() )
 
224
                {
 
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" ) )
 
229
                        {
 
230
                                Status::StatusItem *item = StatusManager::parseStatusItem( childElement );
 
231
                                if ( item )
 
232
                                        group->appendChild( item );
 
233
                        }
 
234
                        childNode = childNode.nextSibling();
 
235
                }
 
236
                return group;
 
237
        }
 
238
        else if ( element.tagName() == QString::fromUtf8( "status" ) )
 
239
        {
 
240
                Status::Status* status = new Status::Status( element.attribute( "uid" ) );
 
241
                status->setCategory( (OnlineStatusManager::Category)element.attribute( "category", "0" ).toInt() );
 
242
                
 
243
                QDomNode childNode = element.firstChild();
 
244
                while ( !childNode.isNull() )
 
245
                {
 
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() );
 
251
 
 
252
                        childNode = childNode.nextSibling();
 
253
                }
 
254
                return status;
 
255
        }
 
256
 
 
257
        return 0;
 
258
}
 
259
 
 
260
void StatusManager::updateUidHash( Status::StatusItem *item )
 
261
{
 
262
        if ( item->isGroup() )
 
263
        {
 
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 );
 
268
        }
 
269
        else
 
270
        {
 
271
                d->uidHash[item->uid()] = item;
 
272
        }
 
273
}
 
274
 
 
275
Status::StatusGroup *StatusManager::defaultStatuses() const
 
276
{
 
277
        Status::StatusGroup* group = new Status::StatusGroup();
 
278
        
 
279
        Status::Status* status = new Status::Status();
 
280
        status->setTitle( i18n( "Online" ) );
 
281
        status->setCategory( OnlineStatusManager::Online );
 
282
        group->appendChild( status );
 
283
 
 
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 );
 
289
 
 
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 );
 
295
 
 
296
        status = new Status::Status();
 
297
        status->setTitle( i18n( "Invisible" ) );
 
298
        status->setCategory( OnlineStatusManager::Invisible );
 
299
        group->appendChild( status );
 
300
 
 
301
        status = new Status::Status();
 
302
        status->setTitle( i18n( "Offline" ) );
 
303
        status->setCategory( OnlineStatusManager::Offline );
 
304
        group->appendChild( status );
 
305
 
 
306
        return group;
 
307
}
 
308
 
 
309
void StatusManager::setGlobalStatus( uint category, const Kopete::StatusMessage &statusMessage )
 
310
{
 
311
        d->globalStatusCategory = category;
 
312
        d->globalStatusMessage = statusMessage;
 
313
 
 
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() );
 
318
        config.sync();
 
319
 
 
320
        emit globalStatusChanged();
 
321
}
 
322
 
 
323
void StatusManager::setGlobalStatusMessage( const Kopete::StatusMessage &statusMessage )
 
324
{
 
325
        d->globalStatusMessage = statusMessage;
 
326
        
 
327
        KConfigGroup config( KGlobal::config(), "Status Manager" );
 
328
        config.writeEntry( "GlobalStatusTitle", d->globalStatusMessage.title() );
 
329
        config.writeEntry( "GlobalStatusMessage", d->globalStatusMessage.message() );
 
330
        config.sync();
 
331
 
 
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 )
 
336
        {
 
337
                Kopete::Contact *self = account->myself();
 
338
                bool isInvisible = self && self->onlineStatus().status() == Kopete::OnlineStatus::Invisible;
 
339
                if ( self && account->isConnected() && !isInvisible )
 
340
                {
 
341
                        account->setOnlineStatus ( self->onlineStatus(), statusMessage );
 
342
                }
 
343
        }
 
344
 
 
345
        emit globalStatusChanged();
 
346
}
 
347
 
 
348
Kopete::StatusMessage StatusManager::globalStatusMessage() const
 
349
{
 
350
        return d->globalStatusMessage;
 
351
}
 
352
 
 
353
uint StatusManager::globalStatusCategory() const
 
354
{
 
355
        return d->globalStatusCategory;
 
356
}
 
357
 
 
358
void StatusManager::askAndSetActive()
 
359
{
 
360
        kDebug(14010) << "Found Activity. Confirming if we should go active";
 
361
 
 
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);
 
369
 
 
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);
 
374
 
 
375
        // If yes is clicked, go online
 
376
        connect(dialog, SIGNAL(yesClicked()), this, SLOT(setActive()));
 
377
 
 
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()));
 
380
 
 
381
        // Show the Dialog
 
382
        dialog->show();
 
383
}
 
384
 
 
385
void StatusManager::setActive()
 
386
{
 
387
        kDebug(14010) << "Found activity on desktop, setting accounts online";
 
388
        if( d->away )
 
389
        {
 
390
                d->away = false;
 
391
                if ( d->goAvailable )
 
392
                {
 
393
                        QList<Kopete::Account*>::iterator it, itEnd = d->autoAwayAccounts.end();
 
394
                        for( it = d->autoAwayAccounts.begin(); it != itEnd; ++it )
 
395
                        {
 
396
                                if( (*it)->isConnected() && (*it)->isAway() )
 
397
                                {
 
398
                                        (*it)->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( (*it)->protocol(),
 
399
                                                Kopete::OnlineStatusManager::Online ), globalStatusMessage(), Kopete::Account::KeepSpecialFlags );
 
400
                                }
 
401
                        }
 
402
                        d->autoAwayAccounts.clear();
 
403
                }
 
404
        }
 
405
}
 
406
 
 
407
void StatusManager::setAutoAway()
 
408
{
 
409
        kDebug(14010) << "Going AutoAway!";
 
410
        if ( !d->away )
 
411
        {
 
412
                d->away = true;
 
413
                
 
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();
 
418
 
 
419
                QList<Kopete::Account*>::iterator it, itEnd = accountList.end();
 
420
                for( it = accountList.begin(); it != itEnd; ++it )
 
421
                {
 
422
                        if( (*it)->myself()->onlineStatus().status() == Kopete::OnlineStatus::Online )
 
423
                        {
 
424
                                d->autoAwayAccounts.append( (*it) );
 
425
                                
 
426
                                if( d->useCustomStatus )
 
427
                                {
 
428
                                        // Display a specific away message
 
429
                                        (*it)->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( (*it)->protocol(),
 
430
                                                Kopete::OnlineStatusManager::Idle ), d->customStatusMessage, Kopete::Account::KeepSpecialFlags );
 
431
                                }
 
432
                                else
 
433
                                {
 
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 );
 
437
                                }
 
438
                        }
 
439
                }
 
440
        }
 
441
}
 
442
 
 
443
bool StatusManager::autoAway()
 
444
{
 
445
        return d->away;
 
446
}
 
447
 
 
448
bool StatusManager::globalAway()
 
449
{
 
450
        return ( d->globalStatusCategory == OnlineStatusManager::Away ||
 
451
                 d->globalStatusCategory == OnlineStatusManager::ExtendedAway ||
 
452
                 d->globalStatusCategory == OnlineStatusManager::Busy ||
 
453
                 d->globalStatusCategory == OnlineStatusManager::Offline );
 
454
}
 
455
 
 
456
void StatusManager::accountUnregistered( const Kopete::Account *account )
 
457
{
 
458
        d->autoAwayAccounts.removeAll( const_cast<Kopete::Account *>(account) );
 
459
}
 
460
 
 
461
void StatusManager::checkIdleTimer()
 
462
{
 
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 );
 
466
 
 
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()) );
 
471
                        else
 
472
                                idleTimer->registerTimeout( d->awayTimeout, this, SLOT(setActive()), SLOT(setAutoAway()) );
 
473
                }
 
474
        }
 
475
}
 
476
 
 
477
void StatusManager::loadSettings()
 
478
{
 
479
        KConfigGroup config( KGlobal::config(), "Status Manager" );
 
480
        d->globalStatusCategory = config.readEntry( "GlobalStatusCategory", 0 );
 
481
 
 
482
        Kopete::StatusMessage statusMessage;
 
483
        statusMessage.setTitle( config.readEntry( "GlobalStatusTitle", QString() ) );
 
484
        statusMessage.setMessage( config.readEntry( "GlobalStatusMessage", QString() ) );
 
485
        d->globalStatusMessage = statusMessage;
 
486
}
 
487
 
 
488
void StatusManager::loadBehaviorSettings()
 
489
{
 
490
        d->awayTimeout = Kopete::BehaviorSettings::self()->autoAwayTimeout();
 
491
        d->goAvailable = Kopete::BehaviorSettings::self()->autoAwayGoAvailable();
 
492
        d->useCustomStatus = Kopete::BehaviorSettings::self()->useCustomAwayMessage();
 
493
        
 
494
        Kopete::StatusMessage customStatusMessage;
 
495
        customStatusMessage.setTitle( Kopete::BehaviorSettings::self()->autoAwayCustomTitle() );
 
496
        customStatusMessage.setMessage( Kopete::BehaviorSettings::self()->autoAwayCustomMessage() );
 
497
        d->customStatusMessage = customStatusMessage;
 
498
 
 
499
        checkIdleTimer();
 
500
}
 
501
 
 
502
}
 
503
 
 
504
#include "kopetestatusmanager.moc"