global-presence.cpp 11.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Global Presence - wraps calls to set and get presence for all accounts.
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "global-presence.h"

23
#include "presence.h"
24

25
26
#include <TelepathyQt/AccountSet>
#include <TelepathyQt/Account>
27
#include <TelepathyQt/PendingReady>
28

29
#include "ktp-debug.h"
30

31
namespace KTp
32
33
{

34
35
GlobalPresence::GlobalPresence(QObject *parent)
    : QObject(parent),
36
      m_connectionStatus(Tp::ConnectionStatusDisconnected),
37
38
      m_changingPresence(false)
{
39
40
41
42
43
    Tp::Presence unknown;
    unknown.setStatus(Tp::ConnectionPresenceTypeUnknown, QLatin1String("unknown"), QString());

    m_requestedPresence = KTp::Presence(unknown);
    m_currentPresence = KTp::Presence(unknown);
44
45
46
47
48
}

void GlobalPresence::setAccountManager(const Tp::AccountManagerPtr &accountManager)
{
    if (! accountManager->isReady()) {
49
        qCWarning(KTP_COMMONINTERNALS) << "GlobalPresence used with unready account manager";
50
51
52
    }

    m_enabledAccounts = accountManager->enabledAccounts();
53
    m_onlineAccounts = accountManager->onlineAccounts();
54
55
56
57
58
59
60
61

    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
        onAccountAdded(account);
    }

    onCurrentPresenceChanged();
    onRequestedPresenceChanged();
    onChangingPresence();
62
    onConnectionStatusChanged();
63
64

    connect(m_enabledAccounts.data(), SIGNAL(accountAdded(Tp::AccountPtr)), SLOT(onAccountAdded(Tp::AccountPtr)));
65
    connect(m_enabledAccounts.data(), SIGNAL(accountRemoved(Tp::AccountPtr)), this, SIGNAL(enabledAccountsChanged()));
66
67
}

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
void GlobalPresence::addAccountManager(const Tp::AccountManagerPtr &accountManager)
{
    m_accountManager = accountManager;
    connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)),
            this, SLOT(onAccountManagerReady(Tp::PendingOperation*)));
}

Tp::AccountManagerPtr GlobalPresence::accountManager() const
{
    return m_accountManager;
}

void GlobalPresence::onAccountManagerReady(Tp::PendingOperation* op)
{
    if (op->isError()) {
83
84
        qCDebug(KTP_COMMONINTERNALS) << op->errorName();
        qCDebug(KTP_COMMONINTERNALS) << op->errorMessage();
85
86

        //TODO: Create signal to send to client
87
        qCDebug(KTP_COMMONINTERNALS) << "Something unexpected happened to the core part of your Instant Messaging system "
88
89
90
91
92
93
94
95
                 << "and it couldn't be initialized. Try restarting the client.";

        return;
    }

    setAccountManager(m_accountManager);
    Q_EMIT(accountManagerReady());
}
96

97
98
99
100
101
Tp::ConnectionStatus GlobalPresence::connectionStatus() const
{
    return m_connectionStatus;
}

102
Presence GlobalPresence::currentPresence() const
103
104
105
106
{
    return m_currentPresence;
}

107
108
109
110
111
112
QString GlobalPresence::currentPresenceMessage() const
{
    KTp::Presence p = currentPresence();
    return p.statusMessage();
}

113
114
115
116
117
QIcon GlobalPresence::currentPresenceIcon() const
{
    return currentPresence().icon();
}

118
119
120
121
122
QString GlobalPresence::currentPresenceIconName() const
{
    return currentPresence().iconName();
}

123
124
125
126
127
QString GlobalPresence::currentPresenceName() const
{
    return currentPresence().displayString();
}

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
GlobalPresence::ConnectionPresenceType GlobalPresence::currentPresenceType() const
{
    KTp::Presence p = currentPresence();
    switch(p.type()) {
        case Tp::ConnectionPresenceTypeAvailable:
            return GlobalPresence::Available;
        case Tp::ConnectionPresenceTypeBusy:
            return GlobalPresence::Busy;
        case Tp::ConnectionPresenceTypeAway:
            return GlobalPresence::Away;
        case Tp::ConnectionPresenceTypeExtendedAway:
            return GlobalPresence::ExtendedAway;
        case Tp::ConnectionPresenceTypeHidden:
            return GlobalPresence::Hidden;
        case Tp::ConnectionPresenceTypeOffline:
            return GlobalPresence::Offline;
        default:
            return GlobalPresence::Unknown;
    }
}

149
Presence GlobalPresence::requestedPresence() const
150
151
152
153
{
    return m_requestedPresence;
}

154
155
156
157
158
QString GlobalPresence::requestedPresenceName() const
{
    return m_requestedPresence.displayString();
}

159
160
bool GlobalPresence::isChangingPresence() const
{
161
    return connectionStatus() == Tp::ConnectionStatusConnecting;
162
163
}

164
void GlobalPresence::setPresence(const KTp::Presence &presence)
165
{
166
    if (m_enabledAccounts.isNull()) {
167
        qCWarning(KTP_COMMONINTERNALS) << "Requested presence change on empty accounts set";
168
169
170
        return;
    }

171
172
173
174
175
    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
        account->setRequestedPresence(presence);
    }
}

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
void GlobalPresence::setPresence(GlobalPresence::ConnectionPresenceType p, QString message)
{
    switch (p) {
    case GlobalPresence::Available:
        setPresence(Tp::Presence::available(message));
        break;
    case GlobalPresence::Busy:
        setPresence(Tp::Presence::busy(message));
        break;
    case GlobalPresence::Away:
        setPresence(Tp::Presence::away(message));
        break;
    case GlobalPresence::ExtendedAway:
        setPresence(Tp::Presence::xa(message));
        break;
    case GlobalPresence::Hidden:
        setPresence(Tp::Presence::hidden(message));
        break;
    case GlobalPresence::Offline:
        setPresence(Tp::Presence::offline(message));
        break;
    default:
198
        qCDebug(KTP_COMMONINTERNALS) << "You should not be here!";
199
200
201
    }
}

202
203
void GlobalPresence::onAccountAdded(const Tp::AccountPtr &account)
{
204
    connect(account.data(), SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)), SLOT(onConnectionStatusChanged()));
205
206
    connect(account.data(), SIGNAL(requestedPresenceChanged(Tp::Presence)), SLOT(onRequestedPresenceChanged()));
    connect(account.data(), SIGNAL(currentPresenceChanged(Tp::Presence)), SLOT(onCurrentPresenceChanged()));
207
208

    Q_EMIT enabledAccountsChanged();
209
210
211
212
}

void GlobalPresence::onCurrentPresenceChanged()
{
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
    /* basic idea of choosing global presence it to make it reflects the presence
     * over all accounts, usually this is used to indicates user the whole system
     * status.
     *
     * If there isn't any account, currentPresence should be offline, since there is nothing
     * online.
     * If there's only one account, then currentPresence should represent the presence
     * of this account.
     * If there're more than one accounts, the situation is more complicated.
     * There can be some accounts is still connecting (thus it's offline), and there can be
     * some accounts doesn't support the presence you're choosing. The user-chosen presence
     * priority will be higher than standard presence order.
     *
     * Example:
     * user choose to be online, 1 account online, 1 account offline, current presence
     * should be online, since online priority is higher than offline.
     * user chooses a presence supported by part of the account, current presence will be
     * the one chosen by user, to indicate there is at least one account supports it.
     * user choose a presence supported by no account, current presence will be chosen
     * from all accounts based on priority, and it also indicates there is no account support
     * the user-chosen presence.
     */
235
236
    Tp::Presence highestCurrentPresence = Tp::Presence::offline();
    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
237
238
239
240
241
        if (account->currentPresence().type() == m_requestedPresence.type()) {
            highestCurrentPresence = account->currentPresence();
            break;
        }

242
        if (Presence::sortPriority(account->currentPresence().type()) < Presence::sortPriority(highestCurrentPresence.type())) {
243
244
245
246
            highestCurrentPresence = account->currentPresence();
        }
    }

247
    qCDebug(KTP_COMMONINTERNALS) << "Current presence changed";
248
249

    if (highestCurrentPresence.type() != m_currentPresence.type() ||
250
251
252
            highestCurrentPresence.status() != m_currentPresence.status() ||
            highestCurrentPresence.statusMessage() != m_currentPresence.statusMessage()) {

253
        m_currentPresence = Presence(highestCurrentPresence);
254
255
        Q_EMIT currentPresenceChanged(m_currentPresence);
    }
256
257

    onChangingPresence();
258
259
260
261
262
263
}

void GlobalPresence::onRequestedPresenceChanged()
{
    Tp::Presence highestRequestedPresence = Tp::Presence::offline();
    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
264
        if (Presence::sortPriority(account->requestedPresence().type()) < Presence::sortPriority(highestRequestedPresence.type())) {
265
            highestRequestedPresence = account->requestedPresence();
266
267
268
        }
    }

269
270
271
    if (highestRequestedPresence.type() != m_requestedPresence.type() ||
            highestRequestedPresence.status() != m_requestedPresence.status() ||
            highestRequestedPresence.statusMessage() != m_requestedPresence.statusMessage()) {
272
        m_requestedPresence = Presence(highestRequestedPresence);
273
274
        // current presence priority is affected by requested presence
        onCurrentPresenceChanged();
275
276
        Q_EMIT requestedPresenceChanged(m_requestedPresence);
    }
277
278

    onChangingPresence();
279
280
281
282
283
284
}

void GlobalPresence::onChangingPresence()
{
    bool isChangingPresence = false;
    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
285
        if (account->requestedPresence().type() != account->currentPresence().type()) {
286
287
288
289
290
291
292
293
294
295
            isChangingPresence = true;
        }
    }

    if (isChangingPresence != m_changingPresence) {
        m_changingPresence = isChangingPresence;
        Q_EMIT changingPresence(m_changingPresence);
    }
}

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
void GlobalPresence::onConnectionStatusChanged()
{
    Tp::ConnectionStatus connectionStatus = Tp::ConnectionStatusDisconnected;

    Q_FOREACH(const Tp::AccountPtr &account, m_enabledAccounts->accounts()) {
        switch (account->connectionStatus()) {
        case Tp::ConnectionStatusConnecting:
            //connecting is the highest state, use this always
            connectionStatus = Tp::ConnectionStatusConnecting;
            break;
        case Tp::ConnectionStatusConnected:
            //only set to connected if we're not at connecting
            if (connectionStatus == Tp::ConnectionStatusDisconnected) {
                connectionStatus = Tp::ConnectionStatusConnected;
            }
            break;
        default:
            break;
        }
    }

    if (connectionStatus != m_connectionStatus) {
        m_connectionStatus = connectionStatus;
        Q_EMIT connectionStatusChanged(m_connectionStatus);
    }
}


324
325
bool GlobalPresence::hasEnabledAccounts() const
{
326
    if (m_enabledAccounts.isNull() || m_enabledAccounts->accounts().isEmpty()) {
327
328
329
330
331
332
333
334
        return false;
    }

    return true;
}

void GlobalPresence::saveCurrentPresence()
{
335
    qCDebug(KTP_COMMONINTERNALS) << "Saving presence with message:" << m_currentPresence.statusMessage();
336
337
338
339
340
    m_savedPresence = m_currentPresence;
}

void GlobalPresence::restoreSavedPresence()
{
341
    qCDebug(KTP_COMMONINTERNALS) << m_savedPresence.statusMessage();
342
343
344
345
346
347
348
349
    setPresence(m_savedPresence);
}

Tp::AccountSetPtr GlobalPresence::onlineAccounts() const
{
    return m_onlineAccounts;
}

350
351
}

352

353
#include "global-presence.moc"